content01
content01

Reputation: 3225

Go encryption differs from Ruby encryption using same key and iv

I have the following Ruby code:

require 'base64'
require 'openssl'

data = '503666666'

key = '4768c01c4f598828ef80d9982d95f888fb952c5b12189c002123e87f751e3e82'

nonce = '4eFi6Q3PX1478767\n'
nonce = Base64.decode64(nonce)

c = OpenSSL::Cipher.new('aes-256-gcm')
c.encrypt
c.key = key
c.iv = nonce

result = c.update(data) + c.final
tag = c.auth_tag

puts Base64.encode64(result + tag) # => J3AVfNG84bz2UuXcfre7LVjSbMpX9XBq6g==\n

that I'm trying to replicate in Golang. Here's what I have so far:

package main

import (
    "fmt"
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "encoding/hex"
)

func main() {
    data := []byte("503666666")

    key, err := hex.DecodeString(`4768c01c4f598828ef80d9982d95f888fb952c5b12189c002123e87f751e3e82`)
    if err != nil {
        panic(err)
    }

    nonceB64 := "4eFi6Q3PX1478767\n"
    nonce, err := base64.StdEncoding.DecodeString(nonceB64)
    if err != nil {
        panic(err)
    }

    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err.Error())
    }

    aesgcm, err := cipher.NewGCM(block)
    if err != nil {
        panic(err.Error())
    }

    ciphertext := aesgcm.Seal(nil, nonce, data, nil)
    fmt.Printf("%s\n", base64.StdEncoding.EncodeToString(ciphertext))
}

However the outcome from the Go version is:

+S52HGbLV1xp+GnF0v8VNOqc5J2GY2+SqA==

vs.

J3AVfNG84bz2UuXcfre7LVjSbMpX9XBq6g==\n

Why am I getting different results?

Thanks,

Upvotes: 3

Views: 556

Answers (1)

Phil Ross
Phil Ross

Reputation: 26090

The AES 256 cipher requires a 32 byte key. The Ruby code is setting the key to a 64 byte string consisting of hexadecimal digits. OpenSSL is truncating the string to 32 bytes before use (change key to '4768c01c4f598828ef80d9982d95f888' in the Ruby code and you'll get the same output).

The Go code however is hex decoding the key before use, converting the 64 hexadecimal digits to the 32 bytes required for the key.

If you want to change the Go code so that it matches the Ruby result, then you'll need to truncate the key and remove the hex decoding step:

key := []byte("4768c01c4f598828ef80d9982d95f888")

However, I'd argue that the key handling in the Go version of the code is better. If you want to change the Ruby version to match the Go version, you can hex decode the key before use:

key = [key].pack('H*')

Upvotes: 5

Related Questions