桥下红药

机器应该工作、人类应该思考

NodeJs与Android用RSA公钥私钥加密解密数据

总分类 0 评

先翻下Nodejs官网的在线文档,因为更新比较快,之前的用法最新版就不一定兼容了,Nodejs加密模块是Crypto ,私钥和公钥直接百度在线生成RSA公钥私钥的网站生成即可。

1. 加密

const crypto = require('crypto');
let str = '我是加密的数据';
//公钥加密
var pub_key = fs.readFileSync('public.key');

let s = crypto.publicEncrypt({key:pub_key,padding:crypto.constants.RSA_PKCS1_PADDING}, new Buffer(str));
//加密后的内容,16进制字符串
console.log(s);

let priv_key = fs.readFileSync('private.key');
let dedata = crypto.privateDecrypt({key:priv_key,padding:crypto.constants.RSA_PKCS1_PADDING},s);
console.log(dedata.toString());

2.Java Rsa 工具类

public class RSAUtils {

    public static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";
    public static final String RSA = "RSA";

    /**
     * 使用公钥加密
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        // 得到公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        byte[] publicKeyBytes = Base64.decode(publicKey, Base64.DEFAULT);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        // 加密数据
        Cipher cp = Cipher.getInstance(TRANSFORMATION);
        cp.init(Cipher.ENCRYPT_MODE, pubKey);
        return cp.doFinal(data);
    }

    /**
     * 使用私钥解密
     */
    public static byte[] decryptByPrivateKey(byte[] encrypted, String privateKey) throws Exception {

        byte[] privateKeyBytes = Base64.decode(privateKey, Base64.DEFAULT);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory kf = KeyFactory.getInstance(RSA);
        PrivateKey keyPrivate = kf.generatePrivate(keySpec);
        // 解密数据
        Cipher cp = Cipher.getInstance(TRANSFORMATION);
        cp.init(Cipher.DECRYPT_MODE, keyPrivate);
        return cp.doFinal(encrypted);
    }


    public static String bytes2HexString(byte[] b) {
        String ret = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase();
        }
        return ret;
    }

    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));

        }
        return d;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

}

3. Run Test

String data = "我是加密的数据";
String public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJhTpp7D3dUefLEbpyHJFugd+3" +
        "Db8VZsvNNnDDcjyOXbB2OTpFVo9Z2+tcHHbQ57Mde9ITaAs2IGQYB4nMJ6HLJvOc" +
        "/g1KNEdRa2AKDIBE1S5Lamg1hD+zmEQz26QDPVzGX2xWzkoPLC+UrLyWDMHytlk/" +
        "b9DV8AdxTkzgYX/CNwIDAQAB";

String private_key = "MIICWwIBAAKBgQCJhTpp7D3dUefLEbpyHJFugd+3Db8VZsvNNnDDcjyOXbB2OTpF" +
        "Vo9Z2+tcHHbQ57Mde9ITaAs2IGQYB4nMJ6HLJvOc/g1KNEdRa2AKDIBE1S5Lamg1" +
        "hD+zmEQz26QDPVzGX2xWzkoPLC+UrLyWDMHytlk/b9DV8AdxTkzgYX/CNwIDAQAB" +
        "AoGANDc1+soMo2BaFqzgkjturPr7KtI5X7LsZzrojg1uGNBSFFGeYn1/aKssLolQ" +
        "Q/n19JfzKBM1TpP17XnPRIk30Q/Pe8WVy6QyvZ1TItojPGtHVqeQFcwwl//5KvTr" +
        "h5X8i+pvEqWlMzUOZKVu7AUMnvnI1b4hGKAcFyoQT2k/MsECQQDSE5VRBYLmzFNd" +
        "qU2HIEuLc7Mw2rhSAzZejwHb0Pn1/LN777fPYmujtyOgbprXk07AX9t5LDb55vF9" +
        "93VT8BZJAkEAp5U4zJO4YrCX6pAtGMwXlyLkcpnSAWgbcehwcekL+qsnmRinga8h" +
        "OdsQGSXtLPIGXn/gah/hfXcME0Agwm8UfwJAeDH+N8o4eEcl16v7kLm4n4RGXUh3" +
        "N21hGT8naBasPcMlCl9AwuZkAdrSBoPiEj/VShpOX4kdt2Qcfd8tASaYCQJAfLij" +
        "ICZkmRaCybDpz0W93N68FMqEMEXR/zGV1kEyiCmve9KMgAjd+pgd4AmI/eVWdihH" +
        "1dPKVz0tgHo+p1ZScwJAUxBp9tcbT2cCjD6vproxdyhjBu6q5pnq5dUWoFiSpExP" +
        "atuMQ80IBlveTFvKQm2HNzm5RcEwoH81UxgHc/Fhmg==";

try {
    byte[] s = RSAUtils.encryptByPublicKey(data.getBytes(), public_key);
    String str = RSAUtils.bytes2HexString(s);// 16进制字符串
    Log.i("tag", str);

    byte[] a = RSAUtils.decryptByPrivateKey(RSAUtils.hexStringToBytes(str), private_key);

    Log.i("tag", new String(a));
} catch (Exception e) {
    e.printStackTrace();
    Log.i("tag", e.getMessage());
}

Java中的公钥私钥去掉头部和尾部 ,而且不能有换行。 使用公钥加密出来的 byte[] 需要 补位 转成hex字符串,用 hex字符串就可以被 NodeJs 用私钥解密。
NodeJs 把 hex 读取到 Buffer Buffer.from(hexString,'hex');


之前一直存在 无法解密的情况,后来发现 NodeJs 的 填充模式是 RSA/ECB/PKCS1Padding ,前后端需要保持一直。

上一篇

发表评论