diff options
Diffstat (limited to 'src/mongo/gotools/vendor/src/github.com/10gen/openssl/ciphers.go')
-rw-r--r-- | src/mongo/gotools/vendor/src/github.com/10gen/openssl/ciphers.go | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/src/mongo/gotools/vendor/src/github.com/10gen/openssl/ciphers.go b/src/mongo/gotools/vendor/src/github.com/10gen/openssl/ciphers.go new file mode 100644 index 00000000000..12662707f54 --- /dev/null +++ b/src/mongo/gotools/vendor/src/github.com/10gen/openssl/ciphers.go @@ -0,0 +1,355 @@ +// Copyright (C) 2014 Space Monkey, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build cgo + +package openssl + +// #include <openssl/evp.h> +// +// int EVP_CIPHER_block_size_not_a_macro(EVP_CIPHER *c) { +// return EVP_CIPHER_block_size(c); +// } +// +// int EVP_CIPHER_key_length_not_a_macro(EVP_CIPHER *c) { +// return EVP_CIPHER_key_length(c); +// } +// +// int EVP_CIPHER_iv_length_not_a_macro(EVP_CIPHER *c) { +// return EVP_CIPHER_iv_length(c); +// } +// +// int EVP_CIPHER_nid_not_a_macro(EVP_CIPHER *c) { +// return EVP_CIPHER_nid(c); +// } +// +// int EVP_CIPHER_CTX_block_size_not_a_macro(EVP_CIPHER_CTX *ctx) { +// return EVP_CIPHER_CTX_block_size(ctx); +// } +// +// int EVP_CIPHER_CTX_key_length_not_a_macro(EVP_CIPHER_CTX *ctx) { +// return EVP_CIPHER_CTX_key_length(ctx); +// } +// +// int EVP_CIPHER_CTX_iv_length_not_a_macro(EVP_CIPHER_CTX *ctx) { +// return EVP_CIPHER_CTX_iv_length(ctx); +// } +// +// const EVP_CIPHER *EVP_CIPHER_CTX_cipher_not_a_macro(EVP_CIPHER_CTX *ctx) { +// return EVP_CIPHER_CTX_cipher(ctx); +// } +import "C" + +import ( + "errors" + "fmt" + "runtime" + "unsafe" +) + +const ( + GCM_TAG_MAXLEN = 16 +) + +type CipherCtx interface { + Cipher() *Cipher + BlockSize() int + KeySize() int + IVSize() int +} + +type Cipher struct { + ptr *C.EVP_CIPHER +} + +func (c *Cipher) Nid() NID { + return NID(C.EVP_CIPHER_nid_not_a_macro(c.ptr)) +} + +func (c *Cipher) ShortName() (string, error) { + return Nid2ShortName(c.Nid()) +} + +func (c *Cipher) BlockSize() int { + return int(C.EVP_CIPHER_block_size_not_a_macro(c.ptr)) +} + +func (c *Cipher) KeySize() int { + return int(C.EVP_CIPHER_key_length_not_a_macro(c.ptr)) +} + +func (c *Cipher) IVSize() int { + return int(C.EVP_CIPHER_iv_length_not_a_macro(c.ptr)) +} + +func Nid2ShortName(nid NID) (string, error) { + sn := C.OBJ_nid2sn(C.int(nid)) + if sn == nil { + return "", fmt.Errorf("NID %d not found", nid) + } + return C.GoString(sn), nil +} + +func GetCipherByName(name string) (*Cipher, error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + p := C.EVP_get_cipherbyname(cname) + if p == nil { + return nil, fmt.Errorf("Cipher %v not found", name) + } + // we can consider ciphers to use static mem; don't need to free + return &Cipher{ptr: p}, nil +} + +func GetCipherByNid(nid NID) (*Cipher, error) { + sn, err := Nid2ShortName(nid) + if err != nil { + return nil, err + } + return GetCipherByName(sn) +} + +type cipherCtx struct { + ctx *C.EVP_CIPHER_CTX +} + +func newCipherCtx() (*cipherCtx, error) { + cctx := C.EVP_CIPHER_CTX_new() + if cctx == nil { + return nil, errors.New("failed to allocate cipher context") + } + ctx := &cipherCtx{cctx} + runtime.SetFinalizer(ctx, func(ctx *cipherCtx) { + C.EVP_CIPHER_CTX_free(ctx.ctx) + }) + return ctx, nil +} + +func (ctx *cipherCtx) applyKeyAndIV(key, iv []byte) error { + var kptr, iptr *C.uchar + if key != nil { + if len(key) != ctx.KeySize() { + return fmt.Errorf("bad key size (%d bytes instead of %d)", + len(key), ctx.KeySize()) + } + kptr = (*C.uchar)(&key[0]) + } + if iv != nil { + if len(iv) != ctx.IVSize() { + return fmt.Errorf("bad IV size (%d bytes instead of %d)", + len(iv), ctx.IVSize()) + } + iptr = (*C.uchar)(&iv[0]) + } + if kptr != nil || iptr != nil { + var res C.int + if ctx.ctx.encrypt != 0 { + res = C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, kptr, iptr) + } else { + res = C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, kptr, iptr) + } + if 1 != res { + return errors.New("failed to apply key/IV") + } + } + return nil +} + +func (ctx *cipherCtx) Cipher() *Cipher { + return &Cipher{ptr: C.EVP_CIPHER_CTX_cipher_not_a_macro(ctx.ctx)} +} + +func (ctx *cipherCtx) BlockSize() int { + return int(C.EVP_CIPHER_CTX_block_size_not_a_macro(ctx.ctx)) +} + +func (ctx *cipherCtx) KeySize() int { + return int(C.EVP_CIPHER_CTX_key_length_not_a_macro(ctx.ctx)) +} + +func (ctx *cipherCtx) IVSize() int { + return int(C.EVP_CIPHER_CTX_iv_length_not_a_macro(ctx.ctx)) +} + +func (ctx *cipherCtx) setCtrl(code, arg int) error { + res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), nil) + if res != 1 { + return fmt.Errorf("failed to set code %d to %d [result %d]", + code, arg, res) + } + return nil +} + +func (ctx *cipherCtx) setCtrlBytes(code, arg int, value []byte) error { + res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), + unsafe.Pointer(&value[0])) + if res != 1 { + return fmt.Errorf("failed to set code %d with arg %d to %x [result %d]", + code, arg, value, res) + } + return nil +} + +func (ctx *cipherCtx) getCtrlInt(code, arg int) (int, error) { + var returnVal C.int + res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), + unsafe.Pointer(&returnVal)) + if res != 1 { + return 0, fmt.Errorf("failed to get code %d with arg %d [result %d]", + code, arg, res) + } + return int(returnVal), nil +} + +func (ctx *cipherCtx) getCtrlBytes(code, arg, expectsize int) ([]byte, error) { + returnVal := make([]byte, expectsize) + res := C.EVP_CIPHER_CTX_ctrl(ctx.ctx, C.int(code), C.int(arg), + unsafe.Pointer(&returnVal[0])) + if res != 1 { + return nil, fmt.Errorf("failed to get code %d with arg %d [result %d]", + code, arg, res) + } + return returnVal, nil +} + +type EncryptionCipherCtx interface { + CipherCtx + + // pass in plaintext, get back ciphertext. can be called + // multiple times as needed + EncryptUpdate(input []byte) ([]byte, error) + + // call after all plaintext has been passed in; may return + // additional ciphertext if needed to finish off a block + // or extra padding information + EncryptFinal() ([]byte, error) +} + +type DecryptionCipherCtx interface { + CipherCtx + + // pass in ciphertext, get back plaintext. can be called + // multiple times as needed + DecryptUpdate(input []byte) ([]byte, error) + + // call after all ciphertext has been passed in; may return + // additional plaintext if needed to finish off a block + DecryptFinal() ([]byte, error) +} + +type encryptionCipherCtx struct { + *cipherCtx +} + +type decryptionCipherCtx struct { + *cipherCtx +} + +func newEncryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) ( + *encryptionCipherCtx, error) { + if c == nil { + return nil, errors.New("null cipher not allowed") + } + ctx, err := newCipherCtx() + if err != nil { + return nil, err + } + var eptr *C.ENGINE + if e != nil { + eptr = e.e + } + if 1 != C.EVP_EncryptInit_ex(ctx.ctx, c.ptr, eptr, nil, nil) { + return nil, errors.New("failed to initialize cipher context") + } + err = ctx.applyKeyAndIV(key, iv) + if err != nil { + return nil, err + } + return &encryptionCipherCtx{cipherCtx: ctx}, nil +} + +func newDecryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) ( + *decryptionCipherCtx, error) { + if c == nil { + return nil, errors.New("null cipher not allowed") + } + ctx, err := newCipherCtx() + if err != nil { + return nil, err + } + var eptr *C.ENGINE + if e != nil { + eptr = e.e + } + if 1 != C.EVP_DecryptInit_ex(ctx.ctx, c.ptr, eptr, nil, nil) { + return nil, errors.New("failed to initialize cipher context") + } + err = ctx.applyKeyAndIV(key, iv) + if err != nil { + return nil, err + } + return &decryptionCipherCtx{cipherCtx: ctx}, nil +} + +func NewEncryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) ( + EncryptionCipherCtx, error) { + return newEncryptionCipherCtx(c, e, key, iv) +} + +func NewDecryptionCipherCtx(c *Cipher, e *Engine, key, iv []byte) ( + DecryptionCipherCtx, error) { + return newDecryptionCipherCtx(c, e, key, iv) +} + +func (ctx *encryptionCipherCtx) EncryptUpdate(input []byte) ([]byte, error) { + outbuf := make([]byte, len(input)+ctx.BlockSize()) + outlen := C.int(len(outbuf)) + res := C.EVP_EncryptUpdate(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen, + (*C.uchar)(&input[0]), C.int(len(input))) + if res != 1 { + return nil, fmt.Errorf("failed to encrypt [result %d]", res) + } + return outbuf[:outlen], nil +} + +func (ctx *decryptionCipherCtx) DecryptUpdate(input []byte) ([]byte, error) { + outbuf := make([]byte, len(input)+ctx.BlockSize()) + outlen := C.int(len(outbuf)) + res := C.EVP_DecryptUpdate(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen, + (*C.uchar)(&input[0]), C.int(len(input))) + if res != 1 { + return nil, fmt.Errorf("failed to decrypt [result %d]", res) + } + return outbuf[:outlen], nil +} + +func (ctx *encryptionCipherCtx) EncryptFinal() ([]byte, error) { + outbuf := make([]byte, ctx.BlockSize()) + var outlen C.int + if 1 != C.EVP_EncryptFinal_ex(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen) { + return nil, errors.New("encryption failed") + } + return outbuf[:outlen], nil +} + +func (ctx *decryptionCipherCtx) DecryptFinal() ([]byte, error) { + outbuf := make([]byte, ctx.BlockSize()) + var outlen C.int + if 1 != C.EVP_DecryptFinal_ex(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen) { + // this may mean the tag failed to verify- all previous plaintext + // returned must be considered faked and invalid + return nil, errors.New("decryption failed") + } + return outbuf[:outlen], nil +} |