golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.73k stars 17.63k forks source link

crypto/cipher: GCM AEAD can be created with a custom nonce OR tag size, but not both #42470

Open rustyx opened 3 years ago

rustyx commented 3 years ago

What version of Go are you using (go version)?

$ go version
go version go1.15 windows/amd64

Does this issue reproduce with the latest release?

Yes, any version, any OS, any CPU.

What did you do?

I need to do AES GCM with both a custom nonce and a custom tag size - 16 and 12 bytes, respectively (the standard is 12 and 16).

The crypto API offers only NewGCMWithNonceSize and NewGCMWithTagSize public API's for creating a cipher with either a custom nonce or a custom tag size, but not both.

I see no technical reason for this limitation given there is a private API that does just that - newGCMWithNonceAndTagSize.

I had no problems doing this in Java and PHP and it's not feasible to change our production encryption because of the Go public API limitation.

What did you expect to see?

I expect the Go public API to allow AES GCM encryption with custom nonce and tag sizes.

What did you see instead?

Instead I'm forced to hack Go and invoke a private API like this

//go:linkname newGCMWithNonceAndTagSize crypto/cipher.newGCMWithNonceAndTagSize
func newGCMWithNonceAndTagSize(cipher cipher.Block, nonceSize, tagSize int) (cipher.AEAD, error)

func Encrypt(s string, key []byte) (string, error) {
    c, err := aes.NewCipher(key)
    if err != nil {
        return "", err
    }
    gcm, err := newGCMWithNonceAndTagSize(c, 16, 12)
    . . .

Works like a charm, but I'd rather use public API's instead.

tmthrgd commented 3 years ago

This was previously discussed in #34594 and declined because no one came forward with any protocol that required both.

rustyx commented 3 years ago

AES GCM is not only for use in a protocol, it's a message encryption standard, see Dworkin, M., "Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC", National Institute of Standards and Technology SP 800-38D, November 2007"

We use it to encrypt messages in our application. Since the messages are short, we shorten the tag from the recommended 16 down to 12 bytes, which provides sufficient security in our case. And we use the GCM built-in nonce strengthening mechanism by supplying a 16-byte plaintext nonce and letting the cipher derive the necessary 12-byte nonce for use in the IV. The derivation is non-trivial and not easily reproduceable before invoking NewGCMWithTagSize.

In other words we could say we have a protocol, but it's not public.

Thus hereby a request to rename newGCMWithNonceAndTagSize to NewGCMWithNonceAndTagSize.

cagedmantis commented 3 years ago

/cc @FiloSottile

darnfish commented 3 years ago

+1 this

Rusted2361 commented 9 months ago

+1 I have a custom encryption done with custom tage and nonce in nodejs this should be part of go private Api

misberner commented 9 months ago

Another aspect is cross-language capability. javax.crypto requires both nonce size and tag length to be specified in GCMParameterSpec.

I don't want to deviate from either the 12 byte nonce or the 16 byte tag, but it would be nice to have constants in both languages that fully describe the behavior for guaranteed interoperability.

ghost commented 8 months ago

I would also like to support this issue. In cryptography, default parameters tend to change as new research emerges and supporting compatibility requires to make these configurable. Only being able to configure one or the other, but not both doesn't lend itself to creating an easy configuration.

gearnode commented 6 months ago

As a maintainer of a Go client for PrivateBin, I've encountered a significant limitation due to the protocol's support for custom nonce sizes and tag sizes. The current state of the public interface hinders the proper implementation of secret decryption according to the PrivateBin protocol standards. Reinstating the newGCMWithNonceAndTagSize function as a public entity would immensely facilitate compliance with these protocol specifications.

FiloSottile commented 6 months ago

@gearnode could you point me to the relevant part of the PrivateBin protocol?

gearnode commented 6 months ago

@FiloSottile

In the PrivateBin protocol, the tag size variable can differ across implementations. Despite this variability, the tag size is consistently specified within the spec object for each implementation[1]. This ensures that clients can dynamically adapt by referencing the spec object to determine the correct tag size for encryption or decryption. The nonce value, crucial for encryption security, is also included in the spec object and is set to 16[2].

Currently, my implementation requires setting a custom nonce size to 16. Additionally, the variable tag size, which is not consistently set to 16 across all implementations, necessitates an hack to accommodate these variations. This requirement to adjust both the nonce and tag sizes, due to the flexibility allowed by the PrivateBin protocol, leads to the need for custom workarounds in the Go environment to ensure compatibility and maintain encryption integrity.

[1] https://github.com/PrivateBin/PrivateBin/wiki/Encryption-format [2] https://github.com/PrivateBin/PrivateBin/blob/master/js/privatebin.js#L1230 [3] https://github.com/PrivateBin/PrivateBin/blob/master/js/types.jsonld#L95

FiloSottile commented 6 months ago

Do you know why PrivateBin supports customizable tag sizes, and/or why it uses 128-bit nonces (which are treated differently from 96-bit nonces in GCM, so don't necessarily provide better security)?

I ask these questions because the goal of Go is not to be universally compatible with every possible configuration, but with useful and/or popular configurations.