移动端和后端加解密
背景
最近做一个加解密的需求,虽然用的标准很老,但是还是被坑到了。
前后端加解密竟然不统一
前端
前端加解密框架的选择较少,我看下来 能用的只有 crypto-js.
并且文档极少,官网实例都没写全,完全要找源代码才能调用。Github 13K star,疯了真的是。
ECB/Pkcs7 实例
const encryptMessage = (msg:string) => {
let keyHex = CryptoJS.enc.Utf8.parse('secret_key');
console.log(keyHex)
return CryptoJS.DES
.encrypt(msg, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
.toString()
}
注意,key 非常关键,如果你传入的是简单的字符串,crypto-js 会计算密钥而不是用这个字符串,这会造成一个问题是 每次加密的结果都是不稳定的。
所以需要把这个 key 转换成 bytes
mode和padding选择也非常坑,最好选择 ECB,padding 不支持 Pkcs5。
而且最好显式的声明出来。
后端
此处用 Java 示例
Bouncy Castle: https://github.com/bcgit/bc-java
Java 这边也是比较坑,刚好 不支持 Pkcs7,即使导入包了,原生的 provider 加密后的结果仍然不匹配。
所以必须要用BC的实现。
ECB/PKCS7Padding 实例
static byte[] desEncrypt(String content, String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, NoSuchProviderException, IllegalBlockSizeException, BadPaddingException {
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
}
static byte[] desDecrypt(byte[] content, String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, NoSuchProviderException, IllegalBlockSizeException, BadPaddingException {
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(content);
}
public static void main(String[] args) {
// https://zhuanlan.zhihu.com/p/40770583
Security.addProvider(new BouncyCastleProvider());
String key = "secret_key";
String encryptText = "encryptText";
try {
byte[] encrypt = desEncrypt(encryptText, key);
System.out.printf("encrypt: %s %n", Base64.encode(encrypt));
byte[] decrypt = desDecrypt(encrypt, key);
System.out.printf("decrypt: %s %n", new String(decrypt));
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException |
BadPaddingException | NoSuchProviderException | IllegalBlockSizeException | InvalidKeySpecException e) {
throw new RuntimeException("encrypt failed", e);
}
}