jerson / react-native-fast-rsa

RSA for react native made with golang for fast performance
https://www.npmjs.com/package/react-native-fast-rsa
MIT License
36 stars 11 forks source link

question: what is public exponent / salt length? #7

Closed davidcallanan closed 3 years ago

davidcallanan commented 4 years ago

I am having problems importing a key created with this library externally and I think this is because the public exponents differ (in my case I am using 65537), or because the salt length differs (mine is 32).

What public exponent do you use?

What value corresponds to the auto salt length?

jerson commented 4 years ago

Hi @davidcallanan thank you for reporting the issue,

salt length is only used with PSS sign or verify and it depends on the language, because some languages like go by default use auto and c# uses equalsHash

Are you trying to create a key pair here and use it to sign on backend ?

Maybe if you had an example of the code you're implementing, I could help you more, something like

keypair=rsa.generate()

//in backend

sign(keypair.public,"sample")

or an example payload to create a test on

https://github.com/jerson/rsa-mobile

and check what happens

davidcallanan commented 4 years ago

I'm not sure why I mentioned salt length, that is only needed for signing/verifying.

I think the problem is the format of the key. I am sending the public key (keyPair.publicKey) over to my backend (minus the header and footer) and the backend is trying import the key using the webcrypto API:

await crypto.subtle.importKey(
    "spki",
    base64.parse(publicKey),
    {
        name: "RSA-PSS",
        modulusLength: 4096,
        publicExponent: new Uint8Array([1, 0, 1]),
        hash: "SHA-256",
    },
    true,
    ["sign", "verify"],
);

This is not working. I probably incorrectly assumed the format was SPKI (PublicKeyInfo ASN1 schema). In what format is the public and private key encoded? Otherwise I have some mistake somewhere else.

jerson commented 4 years ago

@davidcallanan thanks for share the example, I'll be testing to see what the problem might be,

the default public key is PKCS1 but there is a possibility of converting it, I just need to add some methods to the library like

convertPublicKeyToPKIX(publicKey)
convertPublicKeyToPKCS1(publicKey)
convertPublicKeyToJWK(publicKey)
davidcallanan commented 4 years ago

@jerson That would be extremely useful! Otherwise I could see if there is a possibility of supporting PKCS1 in my backend.

jerson commented 4 years ago

hi @davidcallanan i added some new methods may you can use

  static convertPrivateKeyToPKCS8(privateKey: string,): Promise<string>
  static convertPrivateKeyToPKCS1(privateKey: string): Promise<string>
  static async convertPrivateKeyToJWK(privateKey: string): Promise<any>
  static convertPrivateKeyToPublicKey(privateKey: string): Promise<string>

  static convertPublicKeyToPKIX(publicKey: string): Promise<string>
  static convertPublicKeyToPKCS1(publicKey: string): Promise<string>
  static async convertPublicKeyToJWK(publicKey: string): Promise<any>

i suggest to use convertPublicKeyToJWK and convertPrivateKeyToJWK because JWK is a supported format by webcrypto

use 1.5.0 version to use these features

https://www.npmjs.com/package/react-native-fast-rsa/v/1.5.0

davidcallanan commented 4 years ago

I seem to have successfully imported the public key on the backend 👍, but I've been stuck trying to verify a signature the last few days.

Previously I would sign a message using the webcrypto api like this:

let SIGNATURE_ARRAY_BUFFER = await
  crypto.subtle.sign(
    {
      name: "RSA-PSS",
      hash: "SHA-256",
      modulusLength: 4096,
      publicExponent: new Uint8Array([1, 0, 1]),
      saltLength: 32,
    },
    PRIVATE_KEY,
    BINARY_MESSAGE_ARRAY_BUFFER,
  )

I am now trying to do it like this with this package:

let SIGNATURE_ARRAY_BUFFER = await
  RSA.signPSS(
    base64.stringify(new Uint8Array(BINARY_MESSAGE_ARRAY_BUFFER)),
    "sha256",
    "auto",
    PRIVATE_KEY,
  )
  .then(signature => base64.decode(signature).buffer)

I believe it is here that I might have made a mistake. Can you spot anything incorrect here?

I assumed above that I need to use base64 encoding since your API is working with strings instead of array buffers, but maybe that's not the case and so I also tried the following with no luck:

let SIGNATURE_ARRAY_BUFFER = await
  RSA.signPSS(
    new TextDecoder().decode(BINARY_MESSAGE_ARRAY_BUFFER),
    "sha256",
    "auto",
    PRIVATE_KEY,
  )
  .then(signature => new TextEncoder().encode(signature).buffer)

My backend verification code remains the same.