54 lines
1.3 KiB
Go
54 lines
1.3 KiB
Go
package security
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"encoding/base64"
|
|
"errors"
|
|
)
|
|
|
|
func DecryptAESGCM(b64 string, key []byte) (string, error) {
|
|
if len(key) != 32 {
|
|
return "", errors.New("encryption key must be 32 bytes for AES-256")
|
|
}
|
|
raw, err := base64.StdEncoding.DecodeString(b64)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Probar con nonce de 12 y 16 bytes
|
|
for _, ns := range []int{12, 16} {
|
|
gcm, err := cipher.NewGCMWithNonceSize(block, ns)
|
|
if err != nil {
|
|
continue
|
|
} // si no soporta ese ns, prueba el siguiente
|
|
tagSize := gcm.Overhead()
|
|
if len(raw) < ns+tagSize+1 { // al menos 1 byte de CT
|
|
continue
|
|
}
|
|
nonce := raw[:ns]
|
|
rest := raw[ns:]
|
|
|
|
// A) nonce || ciphertext || tag (nativo Go)
|
|
if pt, err := gcm.Open(nil, nonce, rest, nil); err == nil {
|
|
return string(pt), nil
|
|
}
|
|
|
|
// B) nonce || tag || ciphertext (PyCryptodome ejemplo previo)
|
|
if len(rest) > tagSize {
|
|
tag := rest[:tagSize]
|
|
ct := rest[tagSize:]
|
|
repacked := append(ct, tag...) // => ciphertext||tag
|
|
if pt, err := gcm.Open(nil, nonce, repacked, nil); err == nil {
|
|
return string(pt), nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return "", errors.New("GCM auth failed: wrong key, bad data, or unsupported layout")
|
|
}
|