从节点 js 中的存储文件中读取 public 和私钥

Reading public and private key from stored files in node js

我想使用 public 和存储在我系统中的私钥在节点中加密和解密消息。我正在使用以下 java 代码来读取文件并使用密钥。

Java代码:

byte[]  keyBytes = Files.readAllBytes(new File(publicKeyFileName).toPath());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
publicKey=kf.generatePublic(spec);

我可以使用上面的 java 方法毫无问题地从文件中读取 public 键。但是,我想在节点中实现类似的功能。 我曾尝试使用 crypto 来实现相同的目的,但是在将密钥传递给 publicEncrypt 方法时它给了我错误。

节点:

var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey) {
    var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
    var publicKey = fs.read(absolutepath, "utf-8");
    console.log(publicKey);
    var buffer = Buffer.from(toEncrypt);
    var encrypted = crypto.publicEncrypt(publicKey, buffer);
    return encrypted.toString("base64");
};

错误

internal/crypto/cipher.js:43
    return method(toBuf(key), buffer, padding, passphrase);
           ^

Error: error:0906D06C:PEM routines:PEM_read_bio:no start line

请帮忙。谢谢

您的代码或您使用的加密密钥可能存在一些问题:

  1. 您使用的 fs.read 不正确,因为 Node 是异步的,它需要回调函数才能正确读取文件。
  2. 您使用的加密密钥格式不正确 crypto.publicEncrypt。您必须具有正确的 RSA headers.

我修改了你的代码以正确使用 fs.readFile 而不是标准的 Node 回调形式,这里是一个使用正确 RSA 格式的加密密钥示例:

var path = require('path');
var crypto = require('crypto');
var fs = require('fs');

var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey, callback) {
    var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
    fs.readFile(absolutePath, 'utf-8', (err, publicKey) => {
        // The value of `publicKey` is in the callback, not the return value
        console.log(publicKey);
        var buffer = Buffer.from(toEncrypt);
        var encrypted = crypto.publicEncrypt(publicKey, buffer);
        if (err) {
            callback(err);
        } else {
            callback(null, encrypted.toString("base64"));
        }
    });
};

encryptStringWithRsaPublicKey('hello world', 'test.pub', (err, encrypted) => {
    // If you're using a callback in a function,
    // the original function must have a callback as well
    console.log(encrypted);
}); 

test.pub 处的示例加密密钥(必须具有如下所示的 RSA headers):

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA+xGZ/wcz9ugFpP07Nspo6U17l0YhFiFpxxU4pTk3Lifz9R3zsIsu
ERwta7+fWIfxOo208ett/jhskiVodSEt3QBGh4XBipyWopKwZ93HHaDVZAALi/2A
+xTBtWdEo7XGUujKDvC2/aZKukfjpOiUI8AhLAfjmlcD/UZ1QPh0mHsglRNCmpCw
mwSXA9VNmhz+PiB+Dml4WWnKW/VHo2ujTXxq7+efMU4H2fny3Se3KYOsFPFGZ1TN
QSYlFuShWrHPtiLmUdPoP6CV2mML1tk+l7DIIqXrQhLUKDACeM5roMx0kLhUWB8P
+0uj1CNlNN4JRZlC7xFfqiMbFRU9Z4N6YwIDAQAB
-----END RSA PUBLIC KEY-----

截至 2020 年,还有其他方法可以使代码更简洁,例如使用 fs 模块的 Promises 版本和 async / await,尽管我想让这个答案尽可能简单目前可能。

您的问题出在您实际使用 Java 的文件格式上。你可能会保存 private 和编码(“字节数组”)中的 public 到文件并重建密钥,例如和 X509EncodedKeySpec.

此格式与 Node.JS 不兼容,您有 3 种解决方法:

a) 你在 Java 中写入密钥,并使用在 Node.JS

中使用的必要格式

b) 你在 Node.JS 中写了一个转换器以获得正确的格式

c) 使用 OPENSSL 等工具转换文件。

我在这里向您展示“c-way”,因为您只处理一个密钥对,可能不需要编程解决方案。

假设您有两个文件,其中包含私钥 ("rsa_privatekey_2048.der") 和 public 密钥 ("rsa_publickey_2048.der")。

在 OPENSSL 中,您使用命令行

openssl rsa -inform der -in rsa_privatekey_2048.der -outform pem -out rsa_privatekey_2048.pem
openssl rsa -inform der -pubin -in rsa_publickey_2048.der -outform pem -RSAPublicKey_out -out rsa_publickey_2048.pem

将文件转换为 PEM-encoded 格式。

您可以在下面找到我创建的两个示例文件。

rsa_privatekey_2048.pem:

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAmbeKgSAwVe0nZ84XlbDhMkUDjx1C0duA16MkzHTg1uh9SouO
KK0e3gPtTJ9LssaHlXSYhjpMDMWGO6ujd85XRosI2u9eSMNRYY25AQuBriSTVdi9
BHqWAuWuo6VuvTrkgWTL69vNWvLXTOkTiIyrgnhiavjNvm4UVy2AcO2Y3ER+dKgJ
pQAYlEP1jvuQuf6dfNdSBoN0DZbxZXYbQqoA9R/u0GZHCXY+r8A54RejG34pnnuH
koyROZz5H9LbKGOiaETryornQ1TRvB/p9tgIoCJFI71WsKsqeWQPG3Ymg/FoEWXN
Y0yopZEjpkZa3tU+hrOmAFIRg+/bedKfjYFi/QIDAQABAoIBAD3XZ3N3fbq0BExw
z3A7jv3oYfwrq3w+MOGQEvfmdaZANlfNOU4ICAkNz2QqGgw8bsOj+tDVl070EILl
FIjYjKgmu1NJRcdEPPNgTvOqq2th75xz6+dnYf6cZNwVbC3ZCaE86gVjkoRqek/I
3UDsRvvgbsfWfP+Fzc0c0zWbgQnsK6qivU1uzJX+5xsvgQlZboeZOO2lsdQMgfnu
iGlW1bVVM4Sy7AngqfiKMzihUnYEBIi0Y+mfxAPcBLUW8mrOvIOPPuNNUPxUtkBF
bDEzZ6loXCLLD8UBqXeDbCUPPFdTGcc7INhVgFdl2FL6rHB0+p6eUt8MI/XkZI2d
2AnkBUkCgYEA34cKLs2l5bPjyKybbj6ZG7RhDRsnPypEGU63DMV21twISqt7ZQNv
i3iTP+FYHM3ImECbNRIOZpyLuWLPmh5+5egQH13jRDempoxVSVcghbIserlCz2EU
nD2V6ZKuaDbn395O6Qe/PE/yKHLWbXwJrBBm+o7GGNm/Jd3KJib23PcCgYEAsAxB
esEsxxL8hqg/qf+ij7JJt492svpK/6QXhqeeP/FVOtYSgoNtSrXh9qahGpzMSF0m
FqwIgrOX0RkK3v6ofGVfIKObxOVyhwddS1Ru+SnjBFnTMKS57q0WNrIrBNM6Q0xE
Wd3tiljwmg8xF90U/BXu+m0v5XWKxSn7VLiCBqsCgYEAgl0xtSY/EP6fZJQ2ek+L
4DqNN6WUeCRgXxonbA1mR91AALyOVNVyIreJuYHlb7ccvJ9BZexH9dRrMQ3N4ibS
/6cecAzD1S9XxF6oBwQHdbH6ewC9VFFcQdsxKW5gxWrwRQJUp1fbUoOVyb1gDa5/
vZg7VvoZ0rh74Mu/cAzdgPUCgYEAiNANdwt29AKyUyefykpLGCczGL8aPP88l6z7
R38uAX1Ygg/pdJoUrnHo+FkIbHkcXMRfHFF3j7NoMWynwSLg50OUiPX80SiLN5qm
iytDzskZjsEL2gq6IF1NHRabTfWlmrVDjR9mQhTabq+NtIDwlPOqs9100nrlbFIy
6uU0z18CgYEAkDxQg5UjOzbYIighp/e0LkfKlwUE/cMtISUq1A6Yio9AKZYdBV8p
dd4osUW0gZvDflXlQaBIaNlOwl035lyEZtyuKmFh1oSmoir/TTMbIk0avSgKCLGg
fnhabaQRHl4RdXWcEsioRv3aZUsGkb46Y8xODyAUPRHBPhBsd71gnZ8=
-----END RSA PRIVATE KEY-----

rsa_publickey_2048.pem:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAmbeKgSAwVe0nZ84XlbDhMkUDjx1C0duA16MkzHTg1uh9SouOKK0e
3gPtTJ9LssaHlXSYhjpMDMWGO6ujd85XRosI2u9eSMNRYY25AQuBriSTVdi9BHqW
AuWuo6VuvTrkgWTL69vNWvLXTOkTiIyrgnhiavjNvm4UVy2AcO2Y3ER+dKgJpQAY
lEP1jvuQuf6dfNdSBoN0DZbxZXYbQqoA9R/u0GZHCXY+r8A54RejG34pnnuHkoyR
OZz5H9LbKGOiaETryornQ1TRvB/p9tgIoCJFI71WsKsqeWQPG3Ymg/FoEWXNY0yo
pZEjpkZa3tU+hrOmAFIRg+/bedKfjYFi/QIDAQAB
-----END RSA PUBLIC KEY-----