如何使用 node-rsa 加密 node.js 中的数据并解密 android 中的加密数据?
How to encrypt data in node.js using node-rsa and decrypt encrypted data in android?
Node.js 加密代码
function encrypt(msg) {
try {
const public_key = fs.readFileSync(path.join(__dirname, 'PublicKey.pem'), 'utf8');
const encryptStr = crypto.publicEncrypt({
key: public_key,
padding: crypto.constants.RSA_PKCS1_PADDING
}, Buffer.from(msg,'utf8'));
let encryptString = encryptStr.toString('hex');
return encryptString;
} catch (e) {
console.log(e);
return false;
}
}
Android解密代码
public static String decryptStringWithPrivateKey(String s, String keyFilename) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
PrivateKey pkey = readPrivateKeyFromPem(keyFilename);
cipher.init(Cipher.DECRYPT_MODE, pkey);
String dec = new String(cipher.doFinal(Base64.getDecoder().decode(s)), "UTF-8");
return dec;
}
public static PrivateKey readPrivateKeyFromPem(String keyFilename) throws Exception {
byte[] keyBytes = Files.readAllBytes(new File(keyFilename).toPath());
String keyString = new String(keyBytes);
if (keyString.contains("BEGIN PRIVATE KEY")) {
return readPrivateKeyFromPem_PKCS8(keyFilename);
}
else if(keyString.contains("BEGIN RSA PRIVATE KEY")){
return readPrivateKeyFromPem_PKCS1(keyFilename);
}
throw new Exception("Unknown private key format in "+keyFilename);
}
我想在服务器端加密 api 并在 android 设备上解密数据以避免未经授权的访问。
在 android 上解密时“输入字节数组在 172 处的结束字节不正确”
抛出这一错误。
在 NodeJS 代码中,密文是十六进制编码的,在 Java 代码中,它是 Base64 解码的。这个一定要保持一致,两边不是Base64就是十六进制编码。
此外,在Java代码中,在实例化密码时,只指定了算法。这导致使用默认填充,例如在我的机器上(API 28,Android 9 Pie)对应于 RSA/ECB/NoPadding
。这与使用 PKCS#1 v1.5 填充的 NodeJS 端不兼容(除了没有填充的 RSA,所谓的教科书 RSA 是不安全的)。因此,还必须在密码实例化中指定填充 RSA/ECB/PKCS1Padding
.
使用 PKCS#8 格式的私钥和 readPrivateKeyFromPem_PKCS8()
自己的实现,如果上述两个错误得到修复,这两种代码都可以在我的机器上运行。但是,未发布的方法也可能存在缺陷。
Node.js 加密代码
function encrypt(msg) {
try {
const public_key = fs.readFileSync(path.join(__dirname, 'PublicKey.pem'), 'utf8');
const encryptStr = crypto.publicEncrypt({
key: public_key,
padding: crypto.constants.RSA_PKCS1_PADDING
}, Buffer.from(msg,'utf8'));
let encryptString = encryptStr.toString('hex');
return encryptString;
} catch (e) {
console.log(e);
return false;
}
}
Android解密代码
public static String decryptStringWithPrivateKey(String s, String keyFilename) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
PrivateKey pkey = readPrivateKeyFromPem(keyFilename);
cipher.init(Cipher.DECRYPT_MODE, pkey);
String dec = new String(cipher.doFinal(Base64.getDecoder().decode(s)), "UTF-8");
return dec;
}
public static PrivateKey readPrivateKeyFromPem(String keyFilename) throws Exception {
byte[] keyBytes = Files.readAllBytes(new File(keyFilename).toPath());
String keyString = new String(keyBytes);
if (keyString.contains("BEGIN PRIVATE KEY")) {
return readPrivateKeyFromPem_PKCS8(keyFilename);
}
else if(keyString.contains("BEGIN RSA PRIVATE KEY")){
return readPrivateKeyFromPem_PKCS1(keyFilename);
}
throw new Exception("Unknown private key format in "+keyFilename);
}
我想在服务器端加密 api 并在 android 设备上解密数据以避免未经授权的访问。
在 android 上解密时“输入字节数组在 172 处的结束字节不正确” 抛出这一错误。
在 NodeJS 代码中,密文是十六进制编码的,在 Java 代码中,它是 Base64 解码的。这个一定要保持一致,两边不是Base64就是十六进制编码。
此外,在Java代码中,在实例化密码时,只指定了算法。这导致使用默认填充,例如在我的机器上(API 28,Android 9 Pie)对应于 RSA/ECB/NoPadding
。这与使用 PKCS#1 v1.5 填充的 NodeJS 端不兼容(除了没有填充的 RSA,所谓的教科书 RSA 是不安全的)。因此,还必须在密码实例化中指定填充 RSA/ECB/PKCS1Padding
.
使用 PKCS#8 格式的私钥和 readPrivateKeyFromPem_PKCS8()
自己的实现,如果上述两个错误得到修复,这两种代码都可以在我的机器上运行。但是,未发布的方法也可能存在缺陷。