Skip to content

Commit

Permalink
get cipher block size from openssl
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal committed Aug 23, 2023
1 parent 4a5defa commit ed65759
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 59 deletions.
26 changes: 12 additions & 14 deletions aes.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@ import "C"
import (
"crypto/cipher"
"errors"
"runtime"
)

const aesBlockSize = 16

type extraModes interface {
// Copied out of crypto/aes/modes.go.
NewCBCEncrypter(iv []byte) cipher.BlockMode
Expand All @@ -26,22 +23,21 @@ type extraModes interface {
var _ extraModes = (*aesCipher)(nil)

func NewAESCipher(key []byte) (cipher.Block, error) {
c := &evpCipher{key: make([]byte, len(key))}
copy(c.key, key)

switch len(c.key) * 8 {
var kind cipherKind
switch len(key) * 8 {
case 128:
c.kind = cipherAES128
kind = cipherAES128
case 192:
c.kind = cipherAES192
kind = cipherAES192
case 256:
c.kind = cipherAES256
kind = cipherAES256
default:
return nil, errors.New("crypto/aes: invalid key size")
}

runtime.SetFinalizer(c, (*evpCipher).finalize)

c, err := newEVPCipher(key, kind)
if err != nil {
return nil, err
}
return &aesCipher{c}, nil
}

Expand All @@ -55,7 +51,9 @@ type aesCipher struct {
*evpCipher
}

func (c *aesCipher) BlockSize() int { return aesBlockSize }
func (c *aesCipher) BlockSize() int {
return c.blockSize
}

func (c *aesCipher) Encrypt(dst, src []byte) {
c.encrypt(dst, src)
Expand Down
75 changes: 46 additions & 29 deletions cipher.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,23 @@ const (
cipherDES3
)

func (c cipherKind) String() string {
switch c {
case cipherAES128:
return "AES-128"
case cipherAES192:
return "AES-192"
case cipherAES256:
return "AES-256"
case cipherDES:
return "DES"
case cipherDES3:
return "DES3"
default:
panic("unknown cipher kind: " + strconv.Itoa(int(c)))
}
}

type cipherMode int8

const (
Expand Down Expand Up @@ -109,10 +126,23 @@ func loadCipher(k cipherKind, mode cipherMode) (cipher C.GO_EVP_CIPHER_PTR) {
}

type evpCipher struct {
key []byte
enc_ctx C.GO_EVP_CIPHER_CTX_PTR
dec_ctx C.GO_EVP_CIPHER_CTX_PTR
kind cipherKind
key []byte
enc_ctx C.GO_EVP_CIPHER_CTX_PTR
dec_ctx C.GO_EVP_CIPHER_CTX_PTR
kind cipherKind
blockSize int
}

func newEVPCipher(key []byte, kind cipherKind) (*evpCipher, error) {
cipher := loadCipher(kind, cipherModeECB)
if cipher == nil {
return nil, errors.New("crypto/cipher: unsupported cipher: " + kind.String())
}
c := &evpCipher{key: make([]byte, len(key)), kind: kind}
copy(c.key, key)
c.blockSize = int(C.go_openssl_EVP_CIPHER_get_block_size(cipher))
runtime.SetFinalizer(c, (*evpCipher).finalize)
return c, nil
}

func (c *evpCipher) finalize() {
Expand All @@ -124,28 +154,16 @@ func (c *evpCipher) finalize() {
}
}

func (c *evpCipher) blockSize() int {
switch c.kind {
case cipherAES128, cipherAES192, cipherAES256:
return aesBlockSize
case cipherDES, cipherDES3:
return desBlockSize
default:
panic("openssl: unsupported cipher: " + strconv.Itoa(int(c.kind)))
}
}

func (c *evpCipher) encrypt(dst, src []byte) {
blockSize := c.blockSize()
if len(src) < blockSize {
if len(src) < c.blockSize {
panic("crypto/cipher: input not full block")
}
if len(dst) < blockSize {
if len(dst) < c.blockSize {
panic("crypto/cipher: output not full block")
}
// Only check for overlap between the parts of src and dst that will actually be used.
// This matches Go standard library behavior.
if inexactOverlap(dst[:blockSize], src[:blockSize]) {
if inexactOverlap(dst[:c.blockSize], src[:c.blockSize]) {
panic("crypto/cipher: invalid buffer overlap")
}
if c.enc_ctx == nil {
Expand All @@ -156,23 +174,22 @@ func (c *evpCipher) encrypt(dst, src []byte) {
}
}

if C.go_openssl_EVP_EncryptUpdate_wrapper(c.enc_ctx, base(dst), base(src), C.int(blockSize)) != 1 {
if C.go_openssl_EVP_EncryptUpdate_wrapper(c.enc_ctx, base(dst), base(src), C.int(c.blockSize)) != 1 {
panic("crypto/cipher: EncryptUpdate failed")
}
runtime.KeepAlive(c)
}

func (c *evpCipher) decrypt(dst, src []byte) {
blockSize := c.blockSize()
if len(src) < blockSize {
if len(src) < c.blockSize {
panic("crypto/cipher: input not full block")
}
if len(dst) < blockSize {
if len(dst) < c.blockSize {
panic("crypto/cipher: output not full block")
}
// Only check for overlap between the parts of src and dst that will actually be used.
// This matches Go standard library behavior.
if inexactOverlap(dst[:blockSize], src[:blockSize]) {
if inexactOverlap(dst[:c.blockSize], src[:c.blockSize]) {
panic("crypto/cipher: invalid buffer overlap")
}
if c.dec_ctx == nil {
Expand All @@ -186,7 +203,7 @@ func (c *evpCipher) decrypt(dst, src []byte) {
}
}

C.go_openssl_EVP_DecryptUpdate_wrapper(c.dec_ctx, base(dst), base(src), C.int(blockSize))
C.go_openssl_EVP_DecryptUpdate_wrapper(c.dec_ctx, base(dst), base(src), C.int(c.blockSize))
runtime.KeepAlive(c)
}

Expand Down Expand Up @@ -237,7 +254,7 @@ func (c *evpCipher) newCBC(iv []byte, encrypt bool) cipher.BlockMode {
if err != nil {
panic(err)
}
x := &cipherCBC{ctx: ctx, blockSize: c.blockSize()}
x := &cipherCBC{ctx: ctx, blockSize: c.blockSize}
runtime.SetFinalizer(x, (*cipherCBC).finalize)
if C.go_openssl_EVP_CIPHER_CTX_set_padding(x.ctx, 0) != 1 {
panic("cipher: unable to set padding")
Expand Down Expand Up @@ -298,7 +315,7 @@ type noGCM struct {
}

func (g *noGCM) BlockSize() int {
return g.blockSize()
return g.blockSize
}

func (g *noGCM) Encrypt(dst, src []byte) {
Expand Down Expand Up @@ -328,7 +345,7 @@ func (c *evpCipher) newGCM(tls bool) (cipher.AEAD, error) {
if err != nil {
return nil, err
}
g := &cipherGCM{ctx: ctx, tls: tls, blockSize: c.blockSize()}
g := &cipherGCM{ctx: ctx, tls: tls, blockSize: c.blockSize}
runtime.SetFinalizer(g, (*cipherGCM).finalize)
return g, nil
}
Expand Down Expand Up @@ -455,7 +472,7 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) {
func newCipherCtx(kind cipherKind, mode cipherMode, encrypt int, key, iv []byte) (C.GO_EVP_CIPHER_CTX_PTR, error) {
cipher := loadCipher(kind, mode)
if cipher == nil {
panic("openssl: unsupported cipher: " + strconv.Itoa(int(kind)))
panic("crypto/cipher: unsupported cipher: " + kind.String())
}
ctx := C.go_openssl_EVP_CIPHER_CTX_new()
if ctx == nil {
Expand Down
27 changes: 11 additions & 16 deletions des.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@ import "C"
import (
"crypto/cipher"
"errors"
"runtime"
)

const desBlockSize = 8

// SupportsDESCipher returns true if NewDESCipher is supported.
func SupportsDESCipher() bool {
// True for stock OpenSSL 1.
Expand All @@ -27,28 +24,24 @@ func SupportsTripleDESCipher() bool {
}

func NewDESCipher(key []byte) (cipher.Block, error) {
if !SupportsDESCipher() {
return nil, errors.New("crypto/des: not supported")
}
if len(key) != 8 {
return nil, errors.New("crypto/des: invalid key size")
}
c := &evpCipher{key: make([]byte, len(key)), kind: cipherDES}
copy(c.key, key)
runtime.SetFinalizer(c, (*evpCipher).finalize)
c, err := newEVPCipher(key, cipherDES)
if err != nil {
return nil, err
}
return &desCipher{c}, nil
}

func NewTripleDESCipher(key []byte) (cipher.Block, error) {
if !SupportsTripleDESCipher() {
return nil, errors.New("crypto/des: not supported")
}
if len(key) != 24 {
return nil, errors.New("crypto/des: invalid key size")
}
c := &evpCipher{key: make([]byte, len(key)), kind: cipherDES3}
copy(c.key, key)
runtime.SetFinalizer(c, (*evpCipher).finalize)
c, err := newEVPCipher(key, cipherDES3)
if err != nil {
return nil, err
}
return &desCipher{c}, nil
}

Expand All @@ -63,7 +56,9 @@ type desCipher struct {
*evpCipher
}

func (c *desCipher) BlockSize() int { return desBlockSize }
func (c *desCipher) BlockSize() int {
return c.blockSize
}

func (c *desCipher) Encrypt(dst, src []byte) {
c.encrypt(dst, src)
Expand Down
1 change: 1 addition & 0 deletions shims.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_des_ecb, (void), ()) \
DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_des_cbc, (void), ()) \
DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_des_ede3_ecb, (void), ()) \
DEFINEFUNC(const GO_EVP_CIPHER_PTR, EVP_des_ede3_cbc, (void), ()) \
DEFINEFUNC_RENAMED_3_0(int, EVP_CIPHER_get_block_size, EVP_CIPHER_block_size, (const GO_EVP_CIPHER_PTR cipher), (cipher)) \
DEFINEFUNC(void, EVP_CIPHER_CTX_free, (GO_EVP_CIPHER_CTX_PTR arg0), (arg0)) \
DEFINEFUNC(int, EVP_CIPHER_CTX_ctrl, (GO_EVP_CIPHER_CTX_PTR ctx, int type, int arg, void *ptr), (ctx, type, arg, ptr)) \
DEFINEFUNC(GO_EVP_PKEY_PTR, EVP_PKEY_new, (void), ()) \
Expand Down

0 comments on commit ed65759

Please sign in to comment.