最近做項(xiàng)目,需要服務(wù)器(java寫的)進(jìn)行AES加密,然后iOS解密。這是背景,然后就出現(xiàn)了java AES加密,iOS解密不成功的問題。
網(wǎng)上的說法:發(fā)現(xiàn)在java端和iOS端采用相同明文,相同密鑰加密后的密文不一樣!上網(wǎng)查了資料后發(fā)現(xiàn)iOS中AES加密算法采用的填充是PKCS7Padding,而java不支持PKCS7Padding,只支持PKCS5Padding。我們知道加密算法由算法+模式+填充組成,所以這兩者不同的填充算法導(dǎo)致相同明文相同密鑰加密后出現(xiàn)密文不一致的情況。那么我們需要在java中用PKCS7Padding來填充,這樣就可以和iOS端填充算法一致了。要實(shí)現(xiàn)在java端用PKCS7Padding填充,需要用到bouncycastle組件來實(shí)現(xiàn)。
但是,我不想用bouncycastle,因此就采用了AES/ECB/PKCS5Padding來加密,但是AES/ECB/PKCS5Padding在java中只支持128AES加密。
下面就是我自己的解決方案,話不多說了,直接上java服務(wù)器代碼和iOS客戶端代碼。
- java服務(wù)端代碼
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AESCrypt {
/**
* 對(duì)字符串加密
*
* @param str 加密明文
* @param key 加密秘鑰
* @return 加密密文
*/
public static String Encrytor(String str, String key) {
try {
byte[] raw = key.getBytes("utf-8");
SecretKeySpec spec = new SecretKeySpec(raw, "AES");
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, spec);
byte[] src = str.getBytes("utf-8");
byte[] cipherByte = c.doFinal(src);
return new BASE64Encoder().encode(cipherByte);
//return AESCrypt.encodeBase64(cipherByte);
//return bytesToString(cipherByte);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 對(duì)字符串解密
*
* @param str 解密密文
* @param key 解密秘鑰
* @return 解密明文
*/
public static String Decryptor(String str, String key) {
try {
byte[] raw = key.getBytes("utf-8");
SecretKeySpec spec = new SecretKeySpec(raw, "AES");
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, spec);
byte[] src = new BASE64Decoder().decodeBuffer(str);
byte[] cipherByte = c.doFinal(src);
return new String(cipherByte, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
try {
String password = "123456";
String secretKey = "1234567812345678";
System.out.println(secretKey.length());
System.out.println("SecretKey=" + secretKey);
String encodePwd = AESCrypt.Encrytor(password, secretKey);
System.out.println("encodePwd=" + encodePwd);
String decodePwd = AESCrypt.Decryptor(encodePwd, secretKey);
System.out.println("decodePwd=" + decodePwd);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
注意項(xiàng):
設(shè)置加密形式
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
可以設(shè)置
String secretKey = "1234567812345678"; 必須為16位。
- iOS客戶端代碼
+ (NSString *)aes128DecryptWithText:(NSString *)codeStr key:(NSString *)keyStr{
if (codeStr == nil) return @"";
NSData *cipherData = [self dataWithBase64EncodedString:codeStr];
char keyPtr[kCCKeySizeAES128+1];
bzero(keyPtr, sizeof(keyPtr));
[keyStr getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
size_t bufferSize = [cipherData length] + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
kCCOptionECBMode|kCCOptionPKCS7Padding,
keyPtr,
kCCKeySizeAES128,NULL,
[cipherData bytes],[cipherData length],
buffer, bufferSize,
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
NSData *encryptData = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
return [[NSString alloc] initWithData:encryptData encoding:NSUTF8StringEncoding];
}
free(buffer);
return nil;
}
調(diào)用
NSString * aesDecryptStr = [NSData aes128DecryptWithText:@"mdSm0RmB+xAKrTah3DG31A==" key:"1234567812345678"];
over,希望對(duì)大家有所幫助。