简体   繁体   中英

RSA PKCS1 V1.5 padding encryption in Node js

I wanna encrypt the symmetric session key (which I'm using for AES encryption) with the RSA algorithm with Padding PKCS1 V1.5 but somehow I'm not getting any library that provides this padding (except node-forge) . But in node-forge, I guess the padding is not working correctly, It's breaking on the server side and Saying "Padding is not proper etc".

I tried so many options, I'm referring to the python code(which is working correctly), in that, it provides PKCS1 V1.5 padding properly.

encryptData(sessionKey, publicKey):
        sessionKeyBytes = bytes(sessionKey, 'utf-8')
        key = RSA.import_key(publicKey)
        cipher = PKCS1_v1_5.new(key)
        cipherTextBytes = cipher.encrypt(sessionKeyBytes)
        cipherText = b64encode(cipherTextBytes).decode()

Any library or something that provides this PKCS1 V1.5 padding properly?

Node Js (node-forge) example code

const forge = require("node-forge");
const fs = require("fs");

const Data = "This is a test";

const publicKeyReading = fs.readFileSync("./publicKeyFinal.pem");
const privateKeyReading = fs.readFileSync("./privateKeyFinal.pem");
const publicKeyFromCert = forge.pki.certificateFromPem(publicKeyReading);
const publicKeyToPem = forge.pki.publicKeyToPem(publicKeyFromCert.publicKey);
const publicKeyFromPem = forge.pki.publicKeyFromPem(publicKeyToPem);

const privateKeyFromPem = forge.pki.privateKeyFromPem(privateKeyReading);

const RSAEncryption = publicKeyFromPem.encrypt(Buffer.from(Data));
const RSADecryption = privateKeyFromPem.decrypt(RSAEncryption);

console.log("RSAEncryption", forge.util.encode64(RSAEncryption));
console.log(RSADecryption);

This decryption is working properly here in Node JS but somehow it's breaking on the server side which is written in C#. I tried standard Node Js crypto too but I guess it doesn't provide PKCS1 V1.5 padding for the encryption ( I guess that padding is only for sign ing and verifying in the Node JS standard lib ).

I'm a newbie to asking questions on StackOverflow, so let me know if you need any code or extra info for a better understanding of the problem. I've been working on this project for the past 5 weeks and it's been stuck here for the past 2 weeks.

Thank you in Advance.

Update: As I got know, That Node JS does provide PKCS1 V1.5 padding and I used that but still it's breaking on the server side and I guess that's because of the oaepHash thing in publicEncrypt method. We're using fOEP as false in c# and I'm not able to fix that value as a false in Node Js(and its default value is 'sha1'), So is there any way that I can set the oaepHash value as false or something? Note: I can't change the backend code as per Node JS cause it's working on Java, Python and .net too. I've to figure it out according to the backend code.

C# code

public string DecryptData(EncryptionDecryptionParameterDto encryptionDecryptionParams)
    {
        ValidateDecryptData(encryptionDecryptionParams);
        byte[] numArray = Convert.FromBase64String(encryptionDecryptionParams.CipherText);
        string str = string.Empty;
        var tuple = LoadCertificateAndPrivateKey(encryptionDecryptionParams.PrivateKey, encryptionDecryptionParams.PrivateKeyPassword);
        using (RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider())
        {
            privateKey.ImportParameters(tuple.Item2);
            byte[] numArray1 = null;
            numArray1 = privateKey.Decrypt(numArray, encryptionDecryptionParams.IsOAEPWithSHA1AndMGF1Padding);
            str = Encoding.UTF8.GetString(numArray1);
        }
        return str;
    }

Node Js

const crypto = require("crypto");
const cert = new 
 X509Certificate(Buffer.from(A66ClientRequest.PublicKey));

const encryptedData = crypto.publicEncrypt(
{
  key: cert.publicKey,
  padding: crypto.constants.RSA_PKCS1_PADDING,
},
 Buffer.from(sessionKey),
);

return encryptedData.toString('base64');

LoadCertificateAndPrivateKey() in C#

internal Tuple<Org.BouncyCastle.X509.X509Certificate, RSAParameters> LoadCertificateAndPrivateKey(byte[] privateKey,string pswd)
    {
        using (MemoryStream ms = new MemoryStream(privateKey))
        {

            Pkcs12Store pkcs12 = new Pkcs12Store(ms, pswd.ToArray());
            string keyAlias = pkcs12.Aliases.Cast<string>().FirstOrDefault(p => pkcs12.IsKeyEntry(p));
            return new Tuple<Org.BouncyCastle.X509.X509Certificate, RSAParameters>(pkcs12.GetCertificate(keyAlias).Certificate, DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)pkcs12.GetKey(keyAlias).Key));
        }
    }

ValidateDecryptData() in C#

protected virtual void ValidateDecryptData(EncryptionDecryptionParameterDto encryptionDecryptionParams, bool checkDataLength = false)
    {
        if (!encryptionDecryptionParams.CipherText.HasContent())
        {
            throw new ApplicationException("Cipher Text is missing for RSA decryption.");
        }
        if (encryptionDecryptionParams.PrivateKey == null)
        {
            throw new ApplicationException("Private Key is missing for RSA decryption.");
        }
        if (!encryptionDecryptionParams.PrivateKeyFileName.HasContent())
        {
            throw new ApplicationException("Private Key File Name is missing for RSA decryption.");
        }
        if (encryptionDecryptionParams.IsPrivateKeyPasswordPresent && !encryptionDecryptionParams.PrivateKeyPassword.HasContent())
        {
            throw new ApplicationException("Private Key Password is missing for RSA decryption.");
        }
        if (checkDataLength && encryptionDecryptionParams.DataLength == 0)
        {
            throw new ApplicationException("Data length is missing for RSA decryption.");
        }
        if (encryptionDecryptionParams.SkipMachineKeyFileDeletion ? false : !encryptionDecryptionParams.MachineKeyPath.HasContent())
        {
            throw new ApplicationException("MachineKeyPath is missing");
        }
    }

EncryptionDecryptionParameterDto() in C#

public class EncryptionDecryptionParameterDto
{
    public string SymmetricCode { get; set; }
    public string AsymmetricCode { get; set; }
    public CipherMode CipherMode { get; set; }
    public string CipherText { get; set; }
    public int DataLength { get; set; }
    public string InitailVector { get; set; }
    public string MachineKeyPath { get; set; }
    public string PlainText { get; set; }
    public byte[] PrivateKey { get; set; }
    public string PrivateKeyFileName { get; set; }
    public string PrivateKeyPassword { get; set; }
    public byte[] PublicKey { get; set; }
    public string PublicKeyFileName { get; set; }
    public string SharedKey { get; set; }
    public bool SkipMachineKeyFileDeletion { get; set; }
    public bool IsOAEPWithSHA1AndMGF1Padding { get; set; }
    public bool IsPrivateKeyPasswordPresent { get; set; }
    public string Signature { get; set; }
    public EncryptionDecryptionParameterDto()
    {
        CipherMode = CipherMode.ECB;
    }
}

Update 2: I try to decrypt Python encrypted code with Node Js (to figure out which padding and all working for it) and I found out that python encrypted data was not able to decrypt in Node JS with RSA_PKCS1_PADDING but in python code, they mentioned PKCS1 V1.5 padding and I used same in Node JS (as @Topac said Node Js does provide the padding PKCS1 V1.5) and it's throwing me error rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error . I didn't get this where I'm using the same padding but not be able to decrypt in the Node JS with the same padding and key. I did replace the python example code with the original python code (which I'm referring to) "

So the answer was very simple but kinda tricky to figure out but @Topaco was very helpful. It's just that I was loading pfx files (public and private keys in pfx format) in c# and loading Pem files(Pem formatted keys) in Node JS. I used Pem formatted keys instead of pfx in the c# decryption implementation and it worked like a charm. Thank you @jdweng and @topaco.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM