使用RSA私钥解密Base64字符串

时间:2019-04-15 17:49:23

标签: java node.js

我有一个用RSA公钥加密的字符串,我需要用RSA私钥解密一个字符串。

我已经可以使用Java代码,但是我需要使用Node.js库编写类似的代码来解密我的消息。

这是有效的Java代码,

public static String getDecrypted(String data, String Key) 
      throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
      Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
      PrivateKey pk = KeyFactory.getInstance("RSA").generatePrivate(
          new PKCS8EncodedKeySpec(Base64.getDecoder().decode(Key.getBytes())));
      cipher.init(Cipher.DECRYPT_MODE, pk);
      byte[] encryptedbytes = cipher.doFinal(Base64.getDecoder().decode(data.getBytes()));
      return new String(encryptedbytes);
}

我找不到相同的相应的node.js代码。

我有一个Base64编码的字符串,如下所示

S+JnXECfe8zHO69Mp0oh6ux******.......

并具有如下私钥,

MIIJQgIBADANBgkqhkiG9w0BAQEFAASCC*****............

我无法在带有加密模块的node.js中获得类似的代码。因为我是这个加密模块的新手,所以我不确定我尝试的代码是否正确,

//decryption

const crypto = require('crypto');

const PK_HEADER = '\n-----BEGIN RSA PRIVATE KEY-----\n'
const PK_FOOTER = '\n-----END RSA PRIVATE KEY-----\n'

const pkey ='MIIJQgIBADANBgkqhki......'

const privateKey = `${PK_HEADER}${pkey}${PK_FOOTER}`
const privateEncodedKey = Buffer.from(privateKey, 'base64')

const response = "0f8c396c5279a...";
const decrypt = (privateEncodedKey, message) => {
let enc = crypto.privateDecrypt({
key: privateEncodedKey,
padding: crypto.RSA_PKCS1_OAEP_PADDING
}, Buffer.from(message, 'hex'));
return enc.toString();
};

console.log(decrypt(privateEncodedKey, response ))

您能帮助我们修改node.js加密货币中的代码吗?

这是要解密的详细信息。

算法RSA(Rivest–Shamir–Adleman) 模式ECB(电子密码本) 填充OAEPWithSHA-1AndMGF1Padding

2 个答案:

答案 0 :(得分:0)

元:我很惊讶,这不是骗子,但我找不到。

首先,如果您的数据实际上是用OAEP加密的,则Java代码应该不起作用。 Java(及其他大多数地方)中的PKCS1Padding特别是 PKCSv1.5 填充,现已改名为RSAES-PKCS1-v1_5进行加密(和RSASSA-PKCS1-v1_5进行签名,不适用于此处) 。尽管OAEP在PKCS1v2.0及更高版本中也进行了定义,但在Java中,您应该只为默认值(SHA-1)OAEPPadding或非默认值OAEPwith{hash}andMGF1Padding或第三个init参数指定javax.crypto.spec.OAEPParameterSpec输入PrivateKey

第二,您显示的一部分的base64'd私钥采用PKCS8非加密格式(也称为编码),而不是PKCS1格式。如果是从Java获得的,那是可以预期的。 Java加密对所有算法使用PublicKey的PKCS8格式(对于PRIVATE KEY使用“ X.509”格式)。记录在一个不太明显的位置the superinterface Key中。未加密的PKCS8的正确 PEM类型为RSA PRIVATE KEY -而不是const crypto = require('crypto'); const pk8b64 = ( "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKNwapOQ6rQJHetP"+ "HRlJBIh1OsOsUBiXb3rXXE3xpWAxAha0MH+UPRblOko+5T2JqIb+xKf9Vi3oTM3t"+ "KvffaOPtzKXZauscjq6NGzA3LgeiMy6q19pvkUUOlGYK6+Xfl+B7Xw6+hBMkQuGE"+ "nUS8nkpR5mK4ne7djIyfHFfMu4ptAgMBAAECgYA+s0PPtMq1osG9oi4xoxeAGikf"+ "JB3eMUptP+2DYW7mRibc+ueYKhB9lhcUoKhlQUhL8bUUFVZYakP8xD21thmQqnC4"+ "f63asad0ycteJMLb3r+z26LHuCyOdPg1pyLk3oQ32lVQHBCYathRMcVznxOG16VK"+ "I8BFfstJTaJu0lK/wQJBANYFGusBiZsJQ3utrQMVPpKmloO2++4q1v6ZR4puDQHx"+ "TjLjAIgrkYfwTJBLBRZxec0E7TmuVQ9uJ+wMu/+7zaUCQQDDf2xMnQqYknJoKGq+"+ "oAnyC66UqWC5xAnQS32mlnJ632JXA0pf9pb1SXAYExB1p9Dfqd3VAwQDwBsDDgP6"+ "HD8pAkEA0lscNQZC2TaGtKZk2hXkdcH1SKru/g3vWTkRHxfCAznJUaza1fx0wzdG"+ "GcES1Bdez0tbW4llI5By/skZc2eE3QJAFl6fOskBbGHde3Oce0F+wdZ6XIJhEgCP"+ "iukIcKZoZQzoiMJUoVRrA5gqnmaYDI5uRRl/y57zt6YksR3KcLUIuQJAd242M/WF"+ "6YAZat3q/wEeETeQq1wrooew+8lHl05/Nt0cCpV48RGEhJ83pzBm3mnwHf8lTBJH"+ "x6XroMXsmbnsEw==" ) .replace(/.{64}/g,"$&\n"); const ctxb64 = "QLiNLbAqDPG024Xdtl80OMWCHfPq4pCIduoXKcVyY0211Ji7n6Cvjp+ATyLg95mX"+ "/xuFdLV6jiR0ayVw1KTb+U3WKwQRsAWzA+gYiDjdfRaCrNxtcCp2Onw92bjdjZke"+ "O7VrmzDj+8ovDvDgb/pXhAPMcJKSCDUVXgCxpZSnVJE="; const ctxbuf = Buffer.from(ctxb64,'base64'); // the traditional way const t1 = crypto.privateDecrypt("-----BEGIN PRIVATE KEY-----\n"+pk8b64+"\n-----END PRIVATE KEY-----\n", ctxbuf); console.log(t1); // should work in 11.6.0 (not tested); can add padding: to specify if other than OAEP const t2 = crypto.privateDecrypt({key:Buffer.from(pk8b64,'base64'),format:'der',type:'pkcs8'}, ctxbuf); console.log(t2); ,用于PKCS1。

此外, PEM文件不仅是BEGIN行,一个 base64行和END行。它们是BEGIN行,一个或多个base64行(每64个字符中断)和END行。 nodejs使用OpenSSL,其较旧的版本略微放松了此限制;他们每行最多允许76个字符。较新的版本可以提供更多功能,但是仍然存在限制,我相信您的密钥(显然是4096位或接近)可能会超过它,因此,如果未添加至少一些换行符,它将无法正常工作。

最后,一旦您拥有PEM格式,请使用base64解码。这将在解码中包括BEGIN和END行,从而完全破坏了结果。传统上, nodejs加密的这一部分(以及其他几个部分)接受OpenSSL接受的相同PEM格式;根据doc 11.6.0的规定,可以接受使用OpenSSL的“ DER”格式的替代格式,该格式对应于base64解码实际密钥数据,而不是解码整个PEM(但我没有要测试的新版本)。

因此,这里是一个示例(使用 my 键和数据),两种方法均适用,并假设您正确使用OAEP:

base64encode

答案 1 :(得分:0)

这是上述Java代码中node.js中的等效代码。

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

var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey) {
    var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
    var publicKey = fs.readFileSync(absolutePath, "utf8");
    var buffer = Buffer.from(toEncrypt);
    var encrypted = crypto.publicEncrypt(publicKey, buffer);
    return encrypted.toString("base64");
};

var decryptStringWithRsaPrivateKey = function(toDecrypt, relativeOrAbsolutePathtoPrivateKey) {
    var absolutePath = path.resolve(relativeOrAbsolutePathtoPrivateKey);
    var privateKey = fs.readFileSync(absolutePath, "utf8");
    var buffer = Buffer.from(toDecrypt, "base64");
    console.log("PRIVATE_KEY:",privateKey);
    var decrypted = crypto.privateDecrypt({
        key: privateKey,
        padding:crypto.constants.RSA_PKCS1_OAEP_PADDING
    }, buffer);

    return decrypted.toString("utf8");
};`

cipher= '/**Encrypted TEXT/*'

/*private.pem*/
-----BEGIN PRIVATE KEY-----
............................
-----ENDPRIVATE KEY-----
/**/
const decryptedText = decryptStringWithRsaPrivateKey(cipher,'private.pem')
````````