[英]Android AES 128 encryption
我正在尝试在 Android 上实现 AES128 加密。 我有一个在 iPhone 上使用 Objective C 的解决方案,但无法将其移植到 Android。 我已经在 stackoverflow 上搜索了解决方案,但我似乎做错了什么。 我对 Java 还很陌生,所以我想我错过了一些与数据、字符串转换有关的东西。
这是我的 iPhone 加密:
char keyPtr[kCCKeySizeAES128+1];
[keyString getCString:keyPtr
maxLength:sizeof(keyPtr)
encoding:NSASCIIStringEncoding];
// CString for the plain text
char plainBytes[[plainString length]+1];
[plainString getCString:plainBytes
maxLength:sizeof(plainBytes)
encoding:NSASCIIStringEncoding];
size_t bytesEncrypted = 0;
// Allocate the space for encrypted data
NSUInteger dataLength = [plainString length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);
// Encrypt
CCCryptorStatus ret = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding | kCCOptionECBMode,
keyPtr,
kCCKeySizeAES128,
NULL,
plainBytes, sizeof(plainBytes),
buffer, bufferSize,
&bytesEncrypted);
if (ret != kCCSuccess) {
free(buffer);
}
encryptedData = [NSData dataWithBytes:buffer length:bytesEncrypted];
这是我的Java:
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
在 iPhone 和 Java 中使用相同的密钥和明文会产生不同的结果。 我的 iPhone 结果按我需要的方式工作,所以我试图让 java 给我 iPhone 结果。 我肯定在 Java 中遗漏了一些东西,只是不确定它是什么。
编辑
根据下面的建议,我将我的 Java 修改为这个
byte[] keyBytes = plainTextKey.getBytes("US-ASCII");
SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("US-ASCII"));
但我仍然在 android 和 iPhone 之间得到不同的结果
除了纯文本编码困难(正如 vcsjones 在评论中指出的那样),确保密钥字符串的编码相同(请注意,使用原始字符串,如密码,直接作为加密密钥是个坏消息熊,在密码上使用像 PBKDF2 这样的密钥派生函数来派生密钥)。
此外,用于 ASCII 的 Java 编码字符串是US-ASCII
,而不仅仅是ASCII
,因此请确保在您的getBytes
调用中使用它。
编辑:发现您的问题:iOS 字符串在末尾使用额外的空字符 (0x00) 进行加密,而 java 则没有。 所以在java中加密“hello world\\0”会给你与iOS中“hello world”相同的输出
互联网上的大多数示例都是 AES 的弱实现。 为了实现强大的功能,应该一直使用随机 IV,并且应该对密钥进行散列。
有关 AES 的更安全(随机 IV + 散列密钥)跨平台(android、ios、c#)实现,请在此处查看我的答案 - https://stackoverflow.com/a/24561148/2480840
我已经编写了这个管理器文件,它的功能对我来说非常好。 这是针对 AES 128 的,没有任何盐分。
public class CryptoManager {
private static CryptoManager shared;
private String privateKey = "your_private_key_here";
private String ivString = "your_iv_here";
private CryptoManager(){
}
public static CryptoManager getShared() {
if (shared != null ){
return shared;
}else{
shared = new CryptoManager();
return shared;
}
}
public String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(ivString.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(privateKey.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return android.util.Base64.encodeToString(encrypted, android.util.Base64.DEFAULT);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public String decrypt(String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(ivString.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(privateKey.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = new byte[0];
original = cipher.doFinal(android.util.Base64.decode(encrypted, android.util.Base64.DEFAULT));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
您需要像这样调用函数。
String dataToEncrypt = "I need to encrypt myself";
String encryptedData = CryptoManager.getShared().encrypt(data);
您将使用以下行获得加密字符串
String decryptedString = CryptoManager.getShared().decrypt(encryptedData);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.