AES加密 在PC上和Android上不一样 怎么解决
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AES加密 在PC上和Android上不一样 怎么解决相关的知识,希望对你有一定的参考价值。
参考技术A 你没有指定RNG的Provider未指定的情况下 android 2.3以上版本使用的是 随机数序列是 Android's OpenSSL-backed security provider
以下版本是 BouncyCastle Security Provider
JDK 1.7内没有这个Provider, 这个Android自己搞的,你服务端一定解不出来的。
目前Android支持的 RNG有以下几种
Android's OpenSSL-backed security provider 1ASN.1, DER, PkiPath, PKCS7
BouncyCastle Security Provider v1.49 HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature) Harmony JSSE Provider Android KeyStore security provider
服务端如果也没指定的话,默认使用的是
SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; JavaLoginConfig Configuration)
Oracle JDK 1.7 环境下 支持以下
SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; JavaLoginConfig Configuration)
Sun RSA signature provider
Sun Elliptic Curve provider (EC, ECDSA, ECDH)
Sun JSSE provider(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)
SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC)
Sun (Kerberos v5, SPNEGO)
Sun SASL provider(implements client mechanisms for: DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5, NTLM; server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM)
XMLDSig (DOM XMLSignatureFactory; DOM KeyInfoFactory)
Sun PC/SC provider
Sun's Microsoft Crypto API provider
你们服务端要是用的 什么 OPENJDK 第三方虚拟机,php什么的话,那就只有天知道支不支持了。
不过你看也知道了 JDK里的都是SUN自己搞的, Android JVM里挂载的不是Android专用的就是第三方开源的,我估计你是找不到一样的 随机数生成器 方案了本回答被提问者和网友采纳 参考技术B package cn.com.smartpay.app.http;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* @author carlos carlosk@163.com
* @version 创建时间:2012-5-17 上午9:48:35 类说明
*/
public class AESUtils
public static final String TAG = "AESUtils";
public static String encrypt(String seed, String clearText)
// Log.d(TAG, "加密前的seed=" + seed + ",内容为:" + clearText);
byte[] result = null;
try
byte[] rawkey = getRawKey(seed.getBytes());
result = encrypt(rawkey, clearText.getBytes());
catch (Exception e)
e.printStackTrace();
String content = toHex(result);
// Log.d(TAG, "加密后的内容为:" + content);
return content;
public static String decrypt(String seed, String encrypted)
// Log.d(TAG, "解密前的seed=" + seed + ",内容为:" + encrypted);
byte[] rawKey;
try
rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
String coentn = new String(result);
// Log.d(TAG, "解密后的内容为:" + coentn);
return coentn;
catch (Exception e)
e.printStackTrace();
return null;
private static byte[] getRawKey(byte[] seed) throws Exception
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr);
SecretKey sKey = kgen.generateKey();
byte[] raw = sKey.getEncoded();
return raw;
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Cipher cipher = Cipher.getInstance("AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(
new byte[cipher.getBlockSize()]));
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
private static byte[] decrypt(byte[] raw, byte[] encrypted)
throws Exception
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Cipher cipher = Cipher.getInstance("AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(
new byte[cipher.getBlockSize()]));
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
public static String toHex(String txt)
return toHex(txt.getBytes());
public static String fromHex(String hex)
return new String(toByte(hex));
public static byte[] toByte(String hexString)
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
16).byteValue();
return result;
public static String toHex(byte[] buf)
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++)
appendHex(result, buf[i]);
return result.toString();
private static void appendHex(StringBuffer sb, byte b)
final String HEX = "0123456789ABCDEF";
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
在 Android 和 iPhone 中使用 AES-128 加密(不同的结果)
【中文标题】在 Android 和 iPhone 中使用 AES-128 加密(不同的结果)【英文标题】:Encryption using AES-128 in Android and IPhone (Different result) 【发布时间】:2012-10-29 19:48:09 【问题描述】:我正在尝试在 Android 和 iPhone 平台上使用 AES 算法加密一些文本。我的问题是,即使使用相同的加密/解密算法(AES-128)和相同的固定变量(密钥、IV、模式),我在两个平台上都会得到不同的结果。我包含来自两个平台的代码示例,用于测试加密/解密。在确定我做错了什么时,我将不胜感激。
密钥:“123456789abcdefg” IV:“1111111111111111” 纯文本:“HelloThere” 模式:“AES/CBC/NoPadding”Android 代码:
public class Crypto
private final static String HEX = "0123456789ABCDEF";
public static String encrypt(String seed, String cleartext)
throws Exception
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
public static String decrypt(String seed, String encrypted)
throws Exception
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
private static byte[] getRawKey(byte[] seed) throws Exception
KeyGenerator kgen = KeyGenerator.getInstance("CBC");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
private static byte[] decrypt(byte[] raw, byte[] encrypted)
throws Exception
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
public static String toHex(String txt)
return toHex(txt.getBytes());
public static String fromHex(String hex)
return new String(toByte(hex));
public static byte[] toByte(String hexString)
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
16).byteValue();
return result;
public static String toHex(byte[] buf)
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++)
appendHex(result, buf[i]);
return result.toString();
private static void appendHex(StringBuffer sb, byte b)
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
iPhone(Objective-C)代码:
- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData
NSData* secretKey = [Cipher md5:cipherKey];
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[secretKey bytes], kCCKeySizeAES128, iv, &cryptor);
if (status != kCCSuccess)
return nil;
size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true);
void * buf = malloc(bufsize * sizeof(uint8_t));
memset(buf, 0x0, bufsize);
size_t bufused = 0;
size_t bytesTotal = 0;
status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
buf, bufsize, &bufused);
if (status != kCCSuccess)
free(buf);
CCCryptorRelease(cryptor);
return nil;
bytesTotal += bufused;
status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);
if (status != kCCSuccess)
free(buf);
CCCryptorRelease(cryptor);
return nil;
bytesTotal += bufused;
CCCryptorRelease(cryptor);
return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
+ (NSData *) md5:(NSString *) stringToHash
const char *src = [stringToHash UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(src, strlen(src), result);
return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
我的一些参考资料:
http://code.google.com/p/aes-encryption-samples/wiki/HowToEncryptWithJava http://automagical.rationalmind.net/2009/02/12/aes-interoperability-between-net-and-iphone/ AES interoperability between .Net and iPhone?【问题讨论】:
您使用的是哪种encrypt()
方法?你的问题一团糟。只提供必要的代码。
你可以使用这个解决方案,它对我有用:[在此处输入链接描述][1] [1]:***.com/questions/17535918/…
为什么需要加密数据相等?您可能会无缘无故地降低代码的安全性。在大多数用例中,只有解密的数据必须相等。请参阅 crypto.stackexchange.com/q/5094
codingaffairs.blogspot.com/2016/06/…
【参考方案1】:
注意:对于java中的android
我已经编写了这个管理器文件,它的功能对我来说运行得非常好。这是针对 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);
【讨论】:
【参考方案2】:对于 iPhone,我使用 AESCrypt-ObjC,对于 Android,使用此代码:
public class AESCrypt
private final Cipher cipher;
private final SecretKeySpec key;
private AlgorithmParameterSpec spec;
public AESCrypt(String password) throws Exception
// hash password with SHA-256 and crop the output to 128-bit for key
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(password.getBytes("UTF-8"));
byte[] keyBytes = new byte[32];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
key = new SecretKeySpec(keyBytes, "AES");
spec = getIV();
public AlgorithmParameterSpec getIV()
byte[] iv = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ;
IvParameterSpec ivParameterSpec;
ivParameterSpec = new IvParameterSpec(iv);
return ivParameterSpec;
public String encrypt(String plainText) throws Exception
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
String encryptedText = new String(Base64.encode(encrypted, Base64.DEFAULT), "UTF-8");
return encryptedText;
public String decrypt(String cryptedText) throws Exception
cipher.init(Cipher.DECRYPT_MODE, key, spec);
byte[] bytes = Base64.decode(cryptedText, Base64.DEFAULT);
byte[] decrypted = cipher.doFinal(bytes);
String decryptedText = new String(decrypted, "UTF-8");
return decryptedText;
【讨论】:
@Chris 这样做是为了将 Android 代码与 AESCrypt-ObjC iOS 库对齐。添加 AESCrypt-ObjC 不是我维护的。 上述 Android 代码和 AESCrypt-ObjC iOS 代码与今天一样工作。谢谢。 请注意,如果您重复使用密钥,则使用全零 IV 是不安全的。 复制/粘贴安全不存在。在两个不同的运行时很容易得到相同的结果,诀窍是让它安全。 就我而言,我必须为现有的 iOS 应用程序开发一个 android 应用程序。其中使用算法“kCCOptionPKCS7Padding”和iv使用“kCCBlockSizeAES128”。这个“AES/CBC/PKCS7Padding”等价于 & 必须使用一半的 32 字节密钥将模式设置为 128。否则它使用 AES256。感谢您的回答,这有我想要的一切。【参考方案3】:如果您需要 Android 和 iPhone 的兼容代码示例,请查看适用于 iOS 的 RNCryptor library 和适用于 Java/Android 的 JNCryptor library。
这两个项目都是开源的,并且共享一种通用的数据格式。在这些库中,使用了 256 位 AES,但是如果需要支持 128 位 AES,调整代码将是微不足道的。
根据接受的答案,两个库都使用 PBKDF2。
【讨论】:
【参考方案4】:请参阅我对password-based AES encryption, 的回答,因为您实际上是在使用“种子”作为密码。 (只需将密钥长度从 256 更改为 128,如果这是您想要的。)
试图通过播种具有相同值的 DRBG 来生成相同的密钥是不可靠的。
接下来,您不会在 Android 加密中使用 CBC 或 IV。我的例子也展示了如何正确地做到这一点。顺便说一句,正如我的示例所示,您需要为每条加密的消息生成一个新的 IV,并将其与密文一起发送。否则,使用 CBC 毫无意义。
【讨论】:
【参考方案5】:难怪你得到不同的结果。
您的问题是您滥用 SHA1PRNG 进行密钥派生。 AFAIK 没有共同的标准 SHA1PRNG 如何在内部工作。 AFAIR 甚至 J2SE 和 Bouncycaste 实现使用相同的种子输出不同的结果。
因此,您对getRawKey(byte[] seed)
的实现将为您生成一个随机密钥。如果您使用密钥进行加密,您将获得取决于该密钥的结果。由于密钥是随机的,您不会在 iOS 上获得相同的密钥,因此您会得到不同的结果。
如果您想要一个密钥派生函数,请使用像 PBKDF2 这样的函数,该函数在密钥派生方面几乎完全标准化。
【讨论】:
+1 - 密钥在名称中,伪随机数生成器。即使使用相同的种子,不同的实现也不会给出相同的结果。 首先我要感谢您的反馈,但如果您能提供更多细节或示例,我感谢您的努力,因为这对我来说有点困惑 查看我关于您的 getRawKey(..) 实施的更新答案。 没错。难怪!最糟糕的货运***节目。如果你想让任何程序工作,知道你在做什么会有所帮助,而不是仅仅把你从互联网上复制的代码拼凑在一起。【参考方案6】:在 Android 上,您使用的是getBytes()
。这是一个错误,因为这意味着您使用的是默认字符集而不是已知字符集。请改用getBytes("UTF-8")
,这样您就可以确切地知道您将获得哪些字节。
我不知道 Objective-C 的等价物,但不要依赖默认值。将字符串转换为字节时显式指定 UTF-8。这样,您将在两边获得相同的字节。
我还注意到您在 Objective-C 代码中使用了 MD5,但在 Android 代码中没有。这是故意的吗?
【讨论】:
以上是关于AES加密 在PC上和Android上不一样 怎么解决的主要内容,如果未能解决你的问题,请参考以下文章