C# Client generated RSA-Signature NodeJS server side validation fails

Viewed 91

Dear Community, fast forward. After an initial request I receive an random string from a server. The client(ME) needs to generate an Digital-Signature via C# and send it back to the Node.js API (Express;TypeScript). Then the server validats the signature and returns true, if the signature is successfully verified or false if not. To sign the string I use C# default RSA object and SHA256 for Hashing.

The Server knows my public key and user identifier to make sure the digital-signature belongs to me.


Use-Case Tl;Dr:

Client(C#): Receive a string from the server. Generate an digital-signature(RSA;SHA256) of this string and send it back via API-Request towards the Server.

Server(NodeJS;Express;TypeScript): Receive the request with the digital-signature of the string inside and validats it. Send an answer with true if the signature is successfully verified or false if not.


**The Problem:**

The result turns nerver out as true. Generating an Signature of the string and Verify it localy, both systems (client and server) will return true. Means if the Client generate a signature of the string and verifys it the process results localy in true. If the server uses the same Key-Pair as the client and generate a signature of the same string the process will result in true. BUT using the same Key-Pair both systems generate different signatures for the same string! If I use the digital-signature of the string generated by the server and send it with the client, the server returns TRUE.


Code is a bit different. Names has changed.

Client (C#)

Request Methode

<!-- language: c# -->
    private async Task<string> APIRequestSignature(RSA my_rsa, string randomString)
    {
      byte[] randomBytes = Encoding.UTF8.GetBytes(randomString);
      byte[] signature = Crypto.GetDigitalSignatur256(randomBytes, my_rsa);
    
      MeRequest meRequest = new(identifier, Convert.ToBase64String(signature));
      var request = new HttpRequestMessage
      {
        Method = HttpMethod.Get,
        RequestUri = APIUri.ValidME,
        Content = new StringContent(meRequest.ToString(), Encoding.UTF8, MediaTypeNames.Application.Json),
      };
      var response = await client.SendAsync(request).ConfigureAwait(false);
      response.EnsureSuccessStatusCode();
    
      string responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
      Console.WriteLine(responseBody);
    }
    
        internal class MeRequest: Request
        {
          private string sign;
          public MeRequest(string identifier, string sign) : base(identifier, "")
          {
            this.sign = sign;
          }
          public string signature
          {
            get
            {
              return this.sign;
            }
          }
        }

Crypto Class:

<!-- language: c# -->

    public static byte[] GetDigitalSignatur256(byte[] str, RSA rsa)
    {
      byte[] hash = Hash256(str);
      RSAPKCS1SignatureFormatter rsaFormatter = new(rsa);
      rsaFormatter.SetHashAlgorithm("SHA256");
      return rsaFormatter.CreateSignature(hash);
    }

    public static byte[] Hash256(byte[] arr) =>SHA256.Create().ComputeHash(arr);


Messi JavaScript Server Code: (Node.JS;Express;TypeScript)

<!-- language: lang-js -->
    import \{Encryption\} from "../class/Encryption";
    var randomString = "TESTTESTTESTTEST";

<!-- language: lang-js -->
    //If User Exists need Ident and PKey /Get an random encrypted string
    UserRoutes.get('/UserExist', function(req, res) {
        //Create Hash from randomString
        var hash = crypto.createHash("SHA256");
        hash.update(randomString, "base64");
    
        var randomStringHash = hash.digest("base64");
    
        //Read Private Key from Client for Test Signature
        var clientPrivateKey = fs.readFileSync(config.server.clientKeyPath + "identlarspk.txt", 'utf8');
        //Create Sign with Hash from RandomString
        var sign = crypto.createSign("SHA256");
        sign.update(randomStringHash, "base64");
        sign.end();
        var signature = sign.sign({
            key: clientPrivateKey,
            padding: crypto.constants.RSA_PKCS1_PADDING
        });
        console.log("Signature Created By Server: " + signature);
        res.json({
            randomString: randomString
        })
    
    });

<!-- language: lang-js -->
    //Validate User by Ident and Manipulated random encrypted String By Signature 
    UserRoutes.get('/UserSigning', async function(req, res) {
        var encryption = new Encryption();
        //Formating Public key
        var userPKeyDB = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqdKBCUssRLefK9EzzRKxm+ftQ26PLmI5utmmGY6LgwEnKuIrJw/cWA5Fn+2ebJNAgdH9uFBAh8CEtHHjnfMB0SWCl6Qv8R62x8wJs8xNmoTIVLENe5lvHGi2FLVmzLg1LInfwqfsLBLmCM6re5WtQPX4BiXjfDaeYxYCLg3plfaQyYe9/PCzpswC4U4R3yMKzW3ptj4D+L0BGwp4EKFkh2qGJ1Bnm2PkDwott7CT8a8ef36vS7x1fb0XUuw4b5c87ilQZ+mG85aWDK45R7Tl2ZMebZsAe/kpLIRDsG3nnxdzpBelePFCGWSdCCwvFjygOcLyKXQtqJyp3tHvENGTjQIDAQAB";
        var formatedEncryptionKey = await encryption.FormatePKey(userPKeyDB);
    
        //Create Hash from RandomString
        var hash = crypto.createHash("SHA256");
        hash.update(randomString, "base64");
        var randomStringHash = hash.digest("base64");
        var bufferRandomStringHash = Buffer.from(randomStringHash, "base64");
        var bufferClientSignature = Buffer.from(req.body.signature, "base64");
    
        var verify = crypto.createVerify("SHA256");
        verify.update(randomStringHash);
        verify.end();
        var isValidated = verify.verify(formatedEncryptionKey, bufferClientSignature);
    
        res.json({
            token: isValidated
        })
    
    });

<!-- language: lang-js -->
    //Create start and end points for the Public Key in Encryption Class
    public async FormatePKey(pKey: string): Promise<string> {
        var bufferStartKey = Buffer.from("-----BEGIN PUBLIC KEY-----\n", "utf8");
        var bufferStartKeyUTF8 = bufferStartKey.toString("utf8");
    
        var bufferPubKey = Buffer.from(pKey, "base64");
        var pubKeyBase64 = bufferPubKey.toString("base64");
    
        var bufferEndKey = Buffer.from("\n-----END PUBLIC KEY-----", "utf8");
        var bufferEndKeyUTF8 = bufferEndKey.toString("utf8");
    
    
        var formatedPublicKey = bufferStartKeyUTF8 + pubKeyBase64 + bufferEndKeyUTF8;
    
        var bufferPubicKey = Buffer.from(formatedPublicKey, "utf8");
        var bufferPublicKeyUTF8 = bufferPubicKey.toString("utf8");
    
        return bufferPublicKeyUTF8;
    }
0 Answers
Related