AES/ CBC/ PKCS5Padding加密解密算法和SHA-1散列算法是否适用于所有类型的Android设备
Is AES/ CBC/ PKCS5Padding encryption decryption algorithm and SHA-1 hashing algorithm avaible in all type of Android devices
我曾尝试运行以下AES/CBC/PKCS5Padding加解密代码,用SHA-1作为密钥生成,在 Nexus 5 中。到目前为止效果很好。
然而,我唯一担心的是,AES/ CBC/ PKCS5Padding 加密解密算法和 SHA-1 哈希算法是否适用于所有类型的 Android 设备?
以下代码是否有可能在某些 Android 设备上 运行 失败?如果有,有什么后备方案吗?
AES/CBC/PKCS5Padding
//
public static byte[] generateKey(String key) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] binary = key.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
binary = sha.digest(binary);
// Use only first 128 bit.
binary = Arrays.copyOf(binary, 16);
return binary;
}
//
public static String encrypt(byte[] key, String value) throws GeneralSecurityException {
// Argument validation.
if (key.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
// Setup AES tool.
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
// Do the job with AES tool.
byte[] original = value.getBytes(Charset.forName("UTF-8"));
byte[] binary = cipher.doFinal(original);
return Base64.encodeToString(binary, Base64.DEFAULT);
}
// //
public static String decrypt(byte[] key, String encrypted) throws GeneralSecurityException {
// Argument validation.
if (key.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
// Setup AES tool.
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
// Do the job with AES tool.
byte[] binary = Base64.decode(encrypted, Base64.DEFAULT);
byte[] original = cipher.doFinal(binary);
return new String(original, Charset.forName("UTF-8"));
}
用法
byte[] key = generateKey("my secret key");
String ciphertext = encrypt(key, "my plain content");
String plainContent = decrypt(key, ciphertext);
这不是直接回答您的问题,而是...
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
请勿使用此结构!它会破坏您认为获得的任何安全性!
此调用使用全零初始化向量初始化您的密码对象。这是一件非常非常非常糟糕的事情,尤其是对于 CBC:CBC 具有很强的可塑性,并且不做任何完整性保护。确保使用 SecureRandom
或类似工具生成 IV,最好使用 GCM 或 CCM。
不,不太可能失败。 Android API 派生自 Java API。 Java API 自版本 1.4 以来已包含 "AES/CBC/PKCS5Padding"
。
至于"SHA-1"
,那是更古老的算法,自古以来就得到支持。
请注意不要使用 "PKCS7Padding"
。 Java 使用 "PKCS5Padding"
作为替换,"PKCS7Padding"
支持可能是粗略的,即使它意味着同样的事情。
请注意,您应该 使用基于密码的加密 (PBE) 而不是 AES/CBC 和 SHA-1。特别是使用 SHA-1 作为密钥派生方法特别危险,因为您没有像 PBKDF2 这样的基于密码的密钥派生函数那样使用盐或工作因子。基本上只有当您知道您的密码包含足够的熵时才这样做。
不过,对同一个密钥使用全零 IV 更糟糕(正如评论中已经指出的那样)。它允许攻击者找到重复的(起始块)明文输入。始终建议使用经过身份验证的加密(例如使用 HMAC-SHA-1),传输模式加密或多或少需要这种加密方式(与无法进行 plaintext/padding oracle 攻击的就地加密相反)。
我曾尝试运行以下AES/CBC/PKCS5Padding加解密代码,用SHA-1作为密钥生成,在 Nexus 5 中。到目前为止效果很好。
然而,我唯一担心的是,AES/ CBC/ PKCS5Padding 加密解密算法和 SHA-1 哈希算法是否适用于所有类型的 Android 设备?
以下代码是否有可能在某些 Android 设备上 运行 失败?如果有,有什么后备方案吗?
AES/CBC/PKCS5Padding
//
public static byte[] generateKey(String key) throws GeneralSecurityException, UnsupportedEncodingException {
byte[] binary = key.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
binary = sha.digest(binary);
// Use only first 128 bit.
binary = Arrays.copyOf(binary, 16);
return binary;
}
//
public static String encrypt(byte[] key, String value) throws GeneralSecurityException {
// Argument validation.
if (key.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
// Setup AES tool.
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
// Do the job with AES tool.
byte[] original = value.getBytes(Charset.forName("UTF-8"));
byte[] binary = cipher.doFinal(original);
return Base64.encodeToString(binary, Base64.DEFAULT);
}
// //
public static String decrypt(byte[] key, String encrypted) throws GeneralSecurityException {
// Argument validation.
if (key.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
// Setup AES tool.
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
// Do the job with AES tool.
byte[] binary = Base64.decode(encrypted, Base64.DEFAULT);
byte[] original = cipher.doFinal(binary);
return new String(original, Charset.forName("UTF-8"));
}
用法
byte[] key = generateKey("my secret key");
String ciphertext = encrypt(key, "my plain content");
String plainContent = decrypt(key, ciphertext);
这不是直接回答您的问题,而是...
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
请勿使用此结构!它会破坏您认为获得的任何安全性!
此调用使用全零初始化向量初始化您的密码对象。这是一件非常非常非常糟糕的事情,尤其是对于 CBC:CBC 具有很强的可塑性,并且不做任何完整性保护。确保使用 SecureRandom
或类似工具生成 IV,最好使用 GCM 或 CCM。
不,不太可能失败。 Android API 派生自 Java API。 Java API 自版本 1.4 以来已包含 "AES/CBC/PKCS5Padding"
。
至于"SHA-1"
,那是更古老的算法,自古以来就得到支持。
请注意不要使用 "PKCS7Padding"
。 Java 使用 "PKCS5Padding"
作为替换,"PKCS7Padding"
支持可能是粗略的,即使它意味着同样的事情。
请注意,您应该 使用基于密码的加密 (PBE) 而不是 AES/CBC 和 SHA-1。特别是使用 SHA-1 作为密钥派生方法特别危险,因为您没有像 PBKDF2 这样的基于密码的密钥派生函数那样使用盐或工作因子。基本上只有当您知道您的密码包含足够的熵时才这样做。
不过,对同一个密钥使用全零 IV 更糟糕(正如评论中已经指出的那样)。它允许攻击者找到重复的(起始块)明文输入。始终建议使用经过身份验证的加密(例如使用 HMAC-SHA-1),传输模式加密或多或少需要这种加密方式(与无法进行 plaintext/padding oracle 攻击的就地加密相反)。