最近做项目,需要服务器(java写的)进行AES加密,然后iOS解密。这是背景,然后就出现了java AES加密,iOS解密不成功的问题。
网上的说法:发现在java端和iOS端采用相同明文,相同密钥加密后的密文不一样!上网查了资料后发现iOS中AES加密算法采用的填充是PKCS7Padding,而java不支持PKCS7Padding,只支持PKCS5Padding。我们知道加密算法由算法+模式+填充组成,所以这两者不同的填充算法导致相同明文相同密钥加密后出现密文不一致的情况。那么我们需要在java中用PKCS7Padding来填充,这样就可以和iOS端填充算法一致了。要实现在java端用PKCS7Padding填充,需要用到bouncycastle组件来实现。
但是,我不想用bouncycastle,因此就采用了AES/ECB/PKCS5Padding来加密,但是AES/ECB/PKCS5Padding在java中只支持128AES加密。
下面就是我自己的解决方案,话不多说了,直接上java服务器代码和iOS客户端代码。
- java服务端代码
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AESCrypt {
/**
* 对字符串加密
*
* @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;
}
/**
* 对字符串解密
*
* @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();
}
}
}
注意项:
设置加密形式
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
可以设置
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;
}
调用
NSString * aesDecryptStr = [NSData aes128DecryptWithText:@"mdSm0RmB+xAKrTah3DG31A==" key:"1234567812345678"];
over,希望对大家有所帮助。