Skip to content

Commit 9014635

Browse files
authored
Add new features (#72)
* support AES CTR * support pbkdf2 algorithm and sync * update package version * fix import
1 parent b8caf1b commit 9014635

File tree

7 files changed

+142
-23
lines changed

7 files changed

+142
-23
lines changed

android/src/main/java/com/tectiv3/aes/RCTAes.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
import javax.crypto.SecretKeyFactory;
2424
import javax.crypto.Mac;
2525

26+
import org.spongycastle.crypto.Digest;
27+
import org.spongycastle.crypto.digests.SHA1Digest;
28+
import org.spongycastle.crypto.digests.SHA256Digest;
2629
import org.spongycastle.crypto.digests.SHA512Digest;
2730
import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
2831
import org.spongycastle.crypto.params.KeyParameter;
@@ -40,7 +43,8 @@
4043

4144
public class RCTAes extends ReactContextBaseJavaModule {
4245

43-
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
46+
private static final String CIPHER_CBC_ALGORITHM = "AES/CBC/PKCS7Padding";
47+
private static final String CIPHER_CTR_ALGORITHM = "AES/CTR/PKCS5Padding";
4448
public static final String HMAC_SHA_256 = "HmacSHA256";
4549
public static final String HMAC_SHA_512 = "HmacSHA512";
4650
private static final String KEY_ALGORITHM = "AES";
@@ -57,7 +61,7 @@ public String getName() {
5761
@ReactMethod
5862
public void encrypt(String data, String key, String iv, String algorithm, Promise promise) {
5963
try {
60-
String result = encrypt(data, key, iv);
64+
String result = encrypt(data, key, iv, algorithm.toLowerCase().contains("cbc")?CIPHER_CBC_ALGORITHM:CIPHER_CTR_ALGORITHM);
6165
promise.resolve(result);
6266
} catch (Exception e) {
6367
promise.reject("-1", e.getMessage());
@@ -67,17 +71,22 @@ public void encrypt(String data, String key, String iv, String algorithm, Promis
6771
@ReactMethod
6872
public void decrypt(String data, String pwd, String iv, String algorithm, Promise promise) {
6973
try {
70-
String strs = decrypt(data, pwd, iv);
74+
String strs = decrypt(data, pwd, iv, algorithm.toLowerCase().contains("cbc")?CIPHER_CBC_ALGORITHM:CIPHER_CTR_ALGORITHM);
7175
promise.resolve(strs);
7276
} catch (Exception e) {
7377
promise.reject("-1", e.getMessage());
7478
}
7579
}
7680

81+
@ReactMethod(isBlockingSynchronousMethod = true)
82+
public String pbkdf2Sync(String pwd, String salt, Integer cost, Integer length, String algorithm) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeySpecException {
83+
return pbkdf2(pwd, salt, cost, length, algorithm);
84+
}
85+
7786
@ReactMethod
78-
public void pbkdf2(String pwd, String salt, Integer cost, Integer length, Promise promise) {
87+
public void pbkdf2(String pwd, String salt, Integer cost, Integer length, String algorithm, Promise promise) {
7988
try {
80-
String strs = pbkdf2(pwd, salt, cost, length);
89+
String strs = pbkdf2(pwd, salt, cost, length, algorithm);
8190
promise.resolve(strs);
8291
} catch (Exception e) {
8392
promise.reject("-1", e.getMessage());
@@ -174,11 +183,20 @@ public static String bytesToHex(byte[] bytes) {
174183
}
175184
return new String(hexChars);
176185
}
177-
178-
private static String pbkdf2(String pwd, String salt, Integer cost, Integer length)
186+
private static String pbkdf2(String pwd, String salt, Integer cost, Integer length, String algorithm)
179187
throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException
180188
{
181-
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA512Digest());
189+
Digest algorithmDigest = new SHA512Digest();
190+
if (algorithm.equalsIgnoreCase("sha1")){
191+
algorithmDigest = new SHA1Digest();
192+
}
193+
if (algorithm.equalsIgnoreCase("sha256")){
194+
algorithmDigest = new SHA256Digest();
195+
}
196+
if (algorithm.equalsIgnoreCase("sha512")){
197+
algorithmDigest = new SHA512Digest();
198+
}
199+
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(algorithmDigest);
182200
gen.init(pwd.getBytes("UTF_8"), salt.getBytes("UTF_8"), cost);
183201
byte[] key = ((KeyParameter) gen.generateDerivedParameters(length)).getKey();
184202
return bytesToHex(key);

index.d.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
declare module 'react-native-aes-crypto' {
2-
type Algorithms = 'aes-128-cbc' | 'aes-192-cbc' | 'aes-256-cbc'
3-
4-
function pbkdf2(password: string, salt: string, cost: number, length: number): Promise<string>
2+
type Algorithms = 'aes-128-cbc' | 'aes-192-cbc' | 'aes-256-cbc' | 'aes-128-ctr' | 'aes-192-ctr' | 'aes-256-ctr'
3+
type Algorithms_pbkdf2 = 'sha1' | 'sha256' | 'sha512'
4+
5+
function pbkdf2(password: string, salt: string, cost: number, length: number, algorithm:Algorithms_pbkdf2): Promise<string>
6+
function pbkdf2Sync(password: string, salt: string, cost: number, length: number, algorithm:Algorithms_pbkdf2): string
57
function encrypt(text: string, key: string, iv: string, algorithm: Algorithms): Promise<string>
68
function decrypt(ciphertext: string, key: string, iv: string, algorithm: Algorithms): Promise<string>
79
function hmac256(ciphertext: string, key: string): Promise<string>

ios/RCTAes/RCTAes.m

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,17 @@ @implementation RCTAes
3838
}
3939
}
4040

41+
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(pbkdf2Sync:(NSString *)password salt:(NSString *)salt
42+
cost:(NSInteger)cost length:(NSInteger)length algorithm:(NSString *)algorithm) {
43+
return [AesCrypt pbkdf2:password salt:salt cost:cost length:length algorithm:algorithm];;
44+
}
45+
4146
RCT_EXPORT_METHOD(pbkdf2:(NSString *)password salt:(NSString *)salt
42-
cost:(NSInteger)cost length:(NSInteger)length
47+
cost:(NSInteger)cost length:(NSInteger)length algorithm:(NSString *)algorithm
4348
resolver:(RCTPromiseResolveBlock)resolve
4449
rejecter:(RCTPromiseRejectBlock)reject) {
4550
NSError *error = nil;
46-
NSString *data = [AesCrypt pbkdf2:password salt:salt cost:cost length:length];
51+
NSString *data = [AesCrypt pbkdf2:password salt:salt cost:cost length:length algorithm:algorithm];
4752
if (data == nil) {
4853
reject(@"keygen_fail", @"Key generation failed", error);
4954
} else {

ios/RCTAes/lib/AesCrypt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
@interface AesCrypt : NSObject
1111
+ (NSString *) encrypt: (NSString *)clearText key: (NSString *)key iv: (NSString *)iv algorithm: (NSString *)algorithm;
1212
+ (NSString *) decrypt: (NSString *)cipherText key: (NSString *)key iv: (NSString *)iv algorithm: (NSString *)algorithm;
13-
+ (NSString *) pbkdf2:(NSString *)password salt: (NSString *)salt cost: (NSInteger)cost length: (NSInteger)length;
13+
+ (NSString *) pbkdf2:(NSString *)password salt: (NSString *)salt cost: (NSInteger)cost length: (NSInteger)length algorithm:(NSString *)algorithm;
1414
+ (NSString *) hmac256: (NSString *)input key: (NSString *)key;
1515
+ (NSString *) hmac512: (NSString *)input key: (NSString *)key;
1616
+ (NSString *) sha1: (NSString *)input;

ios/RCTAes/lib/AesCrypt.m

Lines changed: 101 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,33 @@ + (NSData *) fromHex: (NSString *)string {
3535
return data;
3636
}
3737

38-
+ (NSString *) pbkdf2:(NSString *)password salt: (NSString *)salt cost: (NSInteger)cost length: (NSInteger)length {
38+
+ (NSString *) pbkdf2:(NSString *)password salt: (NSString *)salt cost: (NSInteger)cost length: (NSInteger)length algorithm:(NSString *)algorithm{
3939
// Data of String to generate Hash key(hexa decimal string).
4040
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
4141
NSData *saltData = [salt dataUsingEncoding:NSUTF8StringEncoding];
4242

4343
// Hash key (hexa decimal) string data length.
4444
NSMutableData *hashKeyData = [NSMutableData dataWithLength:length/8];
4545

46+
CCPseudoRandomAlgorithm algorithmL = kCCPRFHmacAlgSHA512;
47+
if([algorithm.lowercaseString isEqualToString:@"sha1"]){
48+
algorithmL = kCCPRFHmacAlgSHA1;
49+
}
50+
if([algorithm.lowercaseString isEqualToString:@"sha256"]){
51+
algorithmL = kCCPRFHmacAlgSHA256;
52+
}
53+
if([algorithm.lowercaseString isEqualToString:@"sha512"]){
54+
algorithmL = kCCPRFHmacAlgSHA512;
55+
}
4656
// Key Derivation using PBKDF2 algorithm.
4757
int status = CCKeyDerivationPBKDF(
4858
kCCPBKDF2,
4959
passwordData.bytes,
5060
passwordData.length,
5161
saltData.bytes,
5262
saltData.length,
53-
kCCPRFHmacAlgSHA512,
54-
cost,
63+
algorithmL,
64+
(unsigned int)cost,
5565
hashKeyData.mutableBytes,
5666
hashKeyData.length);
5767

@@ -105,14 +115,98 @@ + (NSData *) AESCBC: (NSString *)operation data: (NSData *)data key: (NSString *
105115
return nil;
106116
}
107117

118+
+ (NSData *) AESCTR: (NSString *)operation data: (NSData *)data key: (NSString *)key iv: (NSString *)iv algorithm: (NSString *)algorithm {
119+
//convert hex string to hex data
120+
NSData *keyData = [self fromHex:key];
121+
NSData *ivData = [self fromHex:iv];
122+
// NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
123+
size_t numBytes = 0;
124+
125+
NSArray *aesAlgorithms = @[@"aes-128-ctr", @"aes-192-ctr", @"aes-256-ctr"];
126+
size_t item = [aesAlgorithms indexOfObject:algorithm];
127+
size_t keyLength;
128+
switch (item) {
129+
case 0:
130+
keyLength = kCCKeySizeAES128;
131+
break;
132+
case 1:
133+
keyLength = kCCKeySizeAES192;
134+
break;
135+
default:
136+
keyLength = kCCKeySizeAES256;
137+
break;
138+
}
139+
140+
NSMutableData * buffer = [[NSMutableData alloc] initWithLength:[data length] + kCCBlockSizeAES128];
141+
142+
CCCryptorRef cryptor = NULL;
143+
144+
CCCryptorStatus cryptStatus = CCCryptorCreateWithMode(
145+
[operation isEqualToString:@"encrypt"] ? kCCEncrypt : kCCDecrypt,
146+
kCCModeCTR,
147+
kCCAlgorithmAES,
148+
ccPKCS7Padding,
149+
ivData.length ? ivData.bytes : nil,
150+
keyData.bytes,
151+
keyLength,
152+
NULL,
153+
0,
154+
0,
155+
kCCModeOptionCTR_BE,
156+
&cryptor);
157+
158+
if (cryptStatus == kCCSuccess) {
159+
//Update Cryptor
160+
CCCryptorStatus update = CCCryptorUpdate(cryptor,
161+
data.bytes,
162+
data.length,
163+
buffer.mutableBytes,
164+
buffer.length,
165+
&numBytes);
166+
if (update == kCCSuccess)
167+
{
168+
//Cut Data Out with nedded length
169+
buffer.length = numBytes;
170+
171+
//Final Cryptor
172+
CCCryptorStatus final = CCCryptorFinal(cryptor, //CCCryptorRef cryptorRef,
173+
buffer.mutableBytes, //void *dataOut,
174+
buffer.length, // size_t dataOutAvailable,
175+
&numBytes); // size_t *dataOutMoved)
176+
177+
if (final == kCCSuccess)
178+
{
179+
//Release Cryptor
180+
//CCCryptorStatus release =
181+
CCCryptorRelease(cryptor); //CCCryptorRef cryptorRef
182+
}
183+
return buffer;
184+
}
185+
}
186+
NSLog(@"AES error, %d", cryptStatus);
187+
return nil;
188+
}
189+
108190
+ (NSString *) encrypt: (NSString *)clearText key: (NSString *)key iv: (NSString *)iv algorithm: (NSString *)algorithm {
109-
NSData *result = [self AESCBC:@"encrypt" data:[clearText dataUsingEncoding:NSUTF8StringEncoding] key:key iv:iv algorithm:algorithm];
110-
return [result base64EncodedStringWithOptions:0];
191+
if ([algorithm containsString:@"ctr"]) {
192+
NSData *result = [self AESCTR:@"encrypt" data:[clearText dataUsingEncoding:NSUTF8StringEncoding] key:key iv:iv algorithm:algorithm];
193+
return [self toHex:result];
194+
}
195+
else{
196+
NSData *result = [self AESCBC:@"encrypt" data:[clearText dataUsingEncoding:NSUTF8StringEncoding] key:key iv:iv algorithm:algorithm];
197+
return [result base64EncodedStringWithOptions:0];
198+
}
111199
}
112200

113201
+ (NSString *) decrypt: (NSString *)cipherText key: (NSString *)key iv: (NSString *)iv algorithm: (NSString *)algorithm {
114-
NSData *result = [self AESCBC:@"decrypt" data:[[NSData alloc] initWithBase64EncodedString:cipherText options:0] key:key iv:iv algorithm:algorithm];
115-
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
202+
if ([algorithm containsString:@"ctr"]) {
203+
NSData *result = [self AESCTR:@"decrypt" data:[self fromHex:cipherText] key:key iv:iv algorithm:algorithm];
204+
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
205+
}
206+
else{
207+
NSData *result = [self AESCBC:@"decrypt" data:[[NSData alloc] initWithBase64EncodedString:cipherText options:0] key:key iv:iv algorithm:algorithm];
208+
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
209+
}
116210
}
117211

118212
+ (NSString *) hmac256: (NSString *)input key: (NSString *)key {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-aes-crypto",
3-
"version": "2.1.1",
3+
"version": "2.1.2",
44
"description": "AES crypto native module for react-native",
55
"main": "index.js",
66
"types": "index.d.ts",

react-native-aes.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Pod::Spec.new do |s|
33
s.name = 'react-native-aes'
4-
s.version = '2.0.0'
4+
s.version = '2.1.2'
55
s.summary = 'Native module for AES encryption'
66
s.author = "tectiv3"
77
s.license = 'MIT'

0 commit comments

Comments
 (0)