stupidgcm: stupidChacha20poly1305.Open: batch C calls in aead_open
Gets the decryption speed to the same level as the encryption speed. internal/speed$ benchstat old.txt new.txt name old time/op new time/op delta StupidXchacha-4 732MB/s ± 0% 740MB/s ± 0% ~ (p=1.000 n=1+1) StupidXchachaDecrypt-4 602MB/s ± 0% 741MB/s ± 0% ~ (p=1.000 n=1+1)
This commit is contained in:
parent
3e27acb989
commit
bf572aef88
@ -9,6 +9,21 @@ static void panic(const char* const msg)
|
|||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const EVP_CIPHER* getEvpCipher(enum aeadType cipherId)
|
||||||
|
{
|
||||||
|
switch (cipherId) {
|
||||||
|
case aeadTypeChacha:
|
||||||
|
return EVP_chacha20_poly1305();
|
||||||
|
case aeadTypeGcm:
|
||||||
|
return EVP_aes_256_gcm();
|
||||||
|
}
|
||||||
|
panic("unknown cipherId");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only support 16-byte tags
|
||||||
|
static const int supportedTagLen = 16;
|
||||||
|
|
||||||
// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode
|
// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode
|
||||||
int aead_seal(
|
int aead_seal(
|
||||||
const enum aeadType cipherId,
|
const enum aeadType cipherId,
|
||||||
@ -23,19 +38,9 @@ int aead_seal(
|
|||||||
unsigned char* const ciphertext,
|
unsigned char* const ciphertext,
|
||||||
const int ciphertextBufLen)
|
const int ciphertextBufLen)
|
||||||
{
|
{
|
||||||
const EVP_CIPHER* evpCipher = NULL;
|
const EVP_CIPHER* evpCipher = getEvpCipher(cipherId);
|
||||||
switch (cipherId) {
|
|
||||||
case aeadTypeChacha:
|
|
||||||
evpCipher = EVP_chacha20_poly1305();
|
|
||||||
break;
|
|
||||||
case aeadTypeGcm:
|
|
||||||
evpCipher = EVP_aes_256_gcm();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("unknown cipherId");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create scratch space "context"
|
// Create scratch space "ctx"
|
||||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
panic("EVP_CIPHER_CTX_new failed");
|
panic("EVP_CIPHER_CTX_new failed");
|
||||||
@ -91,20 +96,99 @@ int aead_seal(
|
|||||||
panic("EVP_EncryptFinal_ex: unexpected length");
|
panic("EVP_EncryptFinal_ex: unexpected length");
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only support 16-byte tags
|
|
||||||
const int tagLen = 16;
|
|
||||||
|
|
||||||
// Get MAC tag and append it to the ciphertext
|
// Get MAC tag and append it to the ciphertext
|
||||||
if (ciphertextLen + tagLen > ciphertextBufLen) {
|
if (ciphertextLen + supportedTagLen > ciphertextBufLen) {
|
||||||
panic("tag overflows output buffer");
|
panic("tag overflows output buffer");
|
||||||
}
|
}
|
||||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tagLen, ciphertext + plaintextLen) != 1) {
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, supportedTagLen, ciphertext + plaintextLen) != 1) {
|
||||||
panic("EVP_CTRL_AEAD_GET_TAG failed");
|
panic("EVP_CTRL_AEAD_GET_TAG failed");
|
||||||
}
|
}
|
||||||
ciphertextLen += tagLen;
|
ciphertextLen += supportedTagLen;
|
||||||
|
|
||||||
// Free scratch space
|
// Free scratch space
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
|
|
||||||
return ciphertextLen;
|
return ciphertextLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int aead_open(
|
||||||
|
const enum aeadType cipherId,
|
||||||
|
const unsigned char* const ciphertext,
|
||||||
|
const int ciphertextLen,
|
||||||
|
const unsigned char* const authData,
|
||||||
|
const int authDataLen,
|
||||||
|
unsigned char* const tag,
|
||||||
|
const int tagLen,
|
||||||
|
const unsigned char* const key,
|
||||||
|
const int keyLen,
|
||||||
|
const unsigned char* const iv,
|
||||||
|
const int ivLen,
|
||||||
|
unsigned char* const plaintext,
|
||||||
|
const int plaintextBufLen)
|
||||||
|
{
|
||||||
|
const EVP_CIPHER* evpCipher = getEvpCipher(cipherId);
|
||||||
|
|
||||||
|
// Create scratch space "ctx"
|
||||||
|
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||||
|
if (!ctx) {
|
||||||
|
panic("EVP_CIPHER_CTX_new failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set cipher
|
||||||
|
if (EVP_DecryptInit_ex(ctx, evpCipher, NULL, NULL, NULL) != 1) {
|
||||||
|
panic("EVP_DecryptInit_ex set cipher failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check keyLen by trying to set it (fails if keyLen != 32)
|
||||||
|
if (EVP_CIPHER_CTX_set_key_length(ctx, keyLen) != 1) {
|
||||||
|
panic("keyLen mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set IV length so we do not depend on the default
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, ivLen, NULL) != 1) {
|
||||||
|
panic("EVP_CTRL_AEAD_SET_IVLEN failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set key and IV
|
||||||
|
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv) != 1) {
|
||||||
|
panic("EVP_DecryptInit_ex set key & iv failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide authentication data
|
||||||
|
int outLen = 0;
|
||||||
|
if (EVP_DecryptUpdate(ctx, NULL, &outLen, authData, authDataLen) != 1) {
|
||||||
|
panic("EVP_DecryptUpdate authData failed");
|
||||||
|
}
|
||||||
|
if (outLen != authDataLen) {
|
||||||
|
panic("EVP_DecryptUpdate authData: unexpected length");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt "ciphertext" into "plaintext"
|
||||||
|
if (ciphertextLen > plaintextBufLen) {
|
||||||
|
panic("ciphertextLen overflows output buffer");
|
||||||
|
}
|
||||||
|
if (EVP_DecryptUpdate(ctx, plaintext, &outLen, ciphertext, ciphertextLen) != 1) {
|
||||||
|
panic("EVP_DecryptUpdate failed");
|
||||||
|
}
|
||||||
|
int plaintextLen = outLen;
|
||||||
|
|
||||||
|
// Check tag
|
||||||
|
if (tagLen != supportedTagLen) {
|
||||||
|
panic("unsupported tag length");
|
||||||
|
}
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tagLen, tag) != 1) {
|
||||||
|
panic("EVP_CTRL_AEAD_SET_TAG failed");
|
||||||
|
}
|
||||||
|
if (EVP_DecryptFinal_ex(ctx, plaintext + plaintextLen, &outLen) != 1) {
|
||||||
|
// authentication failed
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (outLen != 0) {
|
||||||
|
panic("EVP_EncryptFinal_ex: unexpected length");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
|
|
||||||
|
return plaintextLen;
|
||||||
|
}
|
||||||
|
@ -15,3 +15,18 @@ int aead_seal(
|
|||||||
const int ivLen,
|
const int ivLen,
|
||||||
unsigned char* const ciphertext,
|
unsigned char* const ciphertext,
|
||||||
const int ciphertextBufLen);
|
const int ciphertextBufLen);
|
||||||
|
|
||||||
|
int aead_open(
|
||||||
|
const enum aeadType cipherId,
|
||||||
|
const unsigned char* const ciphertext,
|
||||||
|
const int ciphertextLen,
|
||||||
|
const unsigned char* const authData,
|
||||||
|
const int authDataLen,
|
||||||
|
unsigned char* const tag,
|
||||||
|
const int tagLen,
|
||||||
|
const unsigned char* const key,
|
||||||
|
const int keyLen,
|
||||||
|
const unsigned char* const iv,
|
||||||
|
const int ivLen,
|
||||||
|
unsigned char* const plaintext,
|
||||||
|
const int plaintextBufLen);
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/chacha20poly1305"
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
)
|
)
|
||||||
@ -118,59 +117,26 @@ func (g *stupidChacha20poly1305) Open(dst, iv, in, authData []byte) ([]byte, err
|
|||||||
ciphertext := in[:len(in)-tagLen]
|
ciphertext := in[:len(in)-tagLen]
|
||||||
tag := in[len(in)-tagLen:]
|
tag := in[len(in)-tagLen:]
|
||||||
|
|
||||||
// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode
|
res := int(C.aead_open(C.aeadTypeChacha,
|
||||||
|
(*C.uchar)(&ciphertext[0]),
|
||||||
|
C.int(len(ciphertext)),
|
||||||
|
(*C.uchar)(&authData[0]),
|
||||||
|
C.int(len(authData)),
|
||||||
|
(*C.uchar)(&tag[0]),
|
||||||
|
C.int(len(tag)),
|
||||||
|
(*C.uchar)(&g.key[0]),
|
||||||
|
C.int(len(g.key)),
|
||||||
|
(*C.uchar)(&iv[0]),
|
||||||
|
C.int(len(iv)),
|
||||||
|
(*C.uchar)(&buf[0]),
|
||||||
|
C.int(len(buf))))
|
||||||
|
|
||||||
// Create scratch space "context"
|
if res < 0 {
|
||||||
ctx := C.EVP_CIPHER_CTX_new()
|
|
||||||
if ctx == nil {
|
|
||||||
log.Panic("EVP_CIPHER_CTX_new failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set cipher to AES-256
|
|
||||||
if C.EVP_DecryptInit_ex(ctx, C.EVP_chacha20_poly1305(), nil, nil, nil) != 1 {
|
|
||||||
log.Panic("EVP_DecryptInit_ex I failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set key and IV
|
|
||||||
if C.EVP_DecryptInit_ex(ctx, nil, nil, (*C.uchar)(&g.key[0]), (*C.uchar)(&iv[0])) != 1 {
|
|
||||||
log.Panic("EVP_DecryptInit_ex II failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set expected MAC tag
|
|
||||||
if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_AEAD_SET_TAG, tagLen, (unsafe.Pointer)(&tag[0])) != 1 {
|
|
||||||
log.Panic("EVP_CIPHER_CTX_ctrl EVP_CTRL_AEAD_SET_TAG failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide authentication data
|
|
||||||
var resultLen C.int
|
|
||||||
if C.EVP_DecryptUpdate(ctx, nil, &resultLen, (*C.uchar)(&authData[0]), C.int(len(authData))) != 1 {
|
|
||||||
log.Panic("EVP_DecryptUpdate authData failed")
|
|
||||||
}
|
|
||||||
if int(resultLen) != len(authData) {
|
|
||||||
log.Panicf("Unexpected length %d", resultLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt "ciphertext" into "buf"
|
|
||||||
if C.EVP_DecryptUpdate(ctx, (*C.uchar)(&buf[0]), &resultLen, (*C.uchar)(&ciphertext[0]), C.int(len(ciphertext))) != 1 {
|
|
||||||
log.Panic("EVP_DecryptUpdate failed")
|
|
||||||
}
|
|
||||||
if int(resultLen) != len(ciphertext) {
|
|
||||||
log.Panicf("Unexpected length %d", resultLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check MAC
|
|
||||||
dummy := make([]byte, 16)
|
|
||||||
res := C.EVP_DecryptFinal_ex(ctx, (*C.uchar)(&dummy[0]), &resultLen)
|
|
||||||
if resultLen != 0 {
|
|
||||||
log.Panicf("Unexpected length %d", resultLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free scratch space
|
|
||||||
C.EVP_CIPHER_CTX_free(ctx)
|
|
||||||
|
|
||||||
if res != 1 {
|
|
||||||
return nil, ErrAuth
|
return nil, ErrAuth
|
||||||
}
|
}
|
||||||
|
if res != outLen {
|
||||||
|
log.Panicf("unexpected length %d", res)
|
||||||
|
}
|
||||||
|
|
||||||
if inplace {
|
if inplace {
|
||||||
return dst[:len(dst)+outLen], nil
|
return dst[:len(dst)+outLen], nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user