4

We have a encryption mechanism in Go. Input will be like key= "dHRzbGNvbnNlbnR0ZWNobQ==" and text = "1234565434".

  func encrypt(key []byte, text string) (string, error) { 
     block, err := aes.NewCipher(key)
     if err != nil {
        return "", err
    }

     msg := AddPadding([]byte(text))
     ciphertext := make([]byte, aes.BlockSize+len(msg))
     iv := ciphertext[:aes.BlockSize]
     cfb := cipher.NewCFBEncrypter(block, iv)
     cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(msg))
     finalMsg := removeBase64Padding(base64.URLEncoding.EncodeToString(ciphertext))
     return finalMsg, nil
  }


 func AddPadding(src []byte) []byte {
      padding := aes.BlockSize - len(src)%aes.BlockSize
      padtext := bytes.Repeat([]byte{byte(padding)}, padding)
      return append(src, padtext...)
 }

Output is : "AAAAAAAAAAAAAAAAAAAAAEl8eI9S6j7mZTWG0vdwV1A="

I want to replicate the same in NodeJS.

     let iv = 'AAAAAAAAAAAAAAAA';
     let key = "dHRzbGNvbnNlbnR0ZWNobQ==";

     var cipher = crypto.createCipheriv('aes-256-cbc', keyBytes, iv);
     cipher.update(src, 'binary', 'base64');
     let y = cipher.final('base64');
     console.log("y --->> ",y);

But I'm getting error like

   crypto.js:194
   this._handle.initiv(cipher, toBuf(key), toBuf(iv));
           ^
   Error: Invalid key length

Can anyone please suggest me how to do this?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
sai
  • 487
  • 1
  • 7
  • 16
  • 4
    The Go code uses AES-128 and CFB mode, the NodeJS code AES-256 and CBC mode. Why does the Go Code use padding? This is not necessary for CFB. – Topaco Jun 10 '20 at 09:45
  • 1
    Aside: if you want base64 without padding use RawURLEncoding instead of URLEncoding. – Peter Jun 10 '20 at 09:56
  • You must not reuse IVs in CFB mode, and IVs must be unpredicable in CBC mode (https://crypto.stackexchange.com/a/3516/68933, https://stackoverflow.com/a/3008544/603316). – Peter Jun 10 '20 at 10:08
  • @Topaco Thank you for the response. Client is using this kind of encryption from their system, our requirement like is we need to replicate the same in our side. Even after chaning in to AES-128, the encryptions are not same. Do I need to change anything. Kindly suggest me – sai Jun 10 '20 at 10:22
  • @Peter Thnks for your response. But Im not authorized to change anything in GO. I need to make changes in nodejs only. – sai Jun 10 '20 at 10:24
  • 2
    Unfortunately, I can' t reproduce the posted ciphertext with the Go code using the posted data (key and plaintext), neither with AES-128 (assuming a Base64 encoded key) nor with AES-192 (assuming a UTF8 decoded key). Please post the call of the `encrypt` method including all parameters. – Topaco Jun 10 '20 at 11:40
  • 1
    Seems that AES-192 has been used (with UTF8 encoded key). The plaintext was `7989878678` (and not `1234565434`). Could that be? – Topaco Jun 10 '20 at 12:35

1 Answers1

3

The posted ciphertext can be reconstructed with the Go code if UTF-8 encoding is used for the key (and plaintext). The key is therefore 24 bytes in size, i.e. AES-192 is applied.

Note: (1) The key can also be Base64 decoded (AES-128), but this wouldn't produce the posted ciphertext. (2) Furthermore, the posted ciphertext doesn't correspond to the posted plaintext 1234565434, but to the plaintext 7989878678, as the decryption of the ciphertext reveals.

As mode, CFB is used. CFB is a stream cipher mode that doesn't require padding. The crypto module applies padding (PKCS7) by default, but automatically disables it for the stream cipher modes. Since the Go code (with the actually unnecessary padding) is the reference, padding must be forced in the NodeJS code. This is possible e.g. with the pkcs7-padding package.

Furthermore the Go code uses Base64url without padding, which is available e.g. with the base64url package.

The following NodeJS code produces a ciphertext that matches the posted ciphertext:

var crypto = require('crypto');
var pkcs7 = require('pkcs7-padding');
var base64url = require('base64url');

let iv = Buffer.from('00000000000000000000000000000000', 'hex');
let key = Buffer.from('dHRzbGNvbnNlbnR0ZWNobQ==','utf8');
let plaintext = Buffer.from('7989878678','utf8');
let plaintextPadded = pkcs7.pad(plaintext);

let cipher = crypto.createCipheriv('aes-192-cfb', key, iv);
let ivCiphertext = Buffer.concat([iv, cipher.update(plaintextPadded), cipher.final()]);
console.log("ivCiphertext  --->> ", base64url(ivCiphertext));

Note: As already mentioned in the comments, a key/IV pair may only be used once for security reasons, here.

Topaco
  • 40,594
  • 4
  • 35
  • 62