1// Copyright (C) 2017. See AUTHORS. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package openssl 16 17// #include <openssl/evp.h> 18import "C" 19 20import ( 21 "errors" 22 "fmt" 23) 24 25type AuthenticatedEncryptionCipherCtx interface { 26 EncryptionCipherCtx 27 28 // data passed in to ExtraData() is part of the final output; it is 29 // not encrypted itself, but is part of the authenticated data. when 30 // decrypting or authenticating, pass back with the decryption 31 // context's ExtraData() 32 ExtraData([]byte) error 33 34 // use after finalizing encryption to get the authenticating tag 35 GetTag() ([]byte, error) 36} 37 38type AuthenticatedDecryptionCipherCtx interface { 39 DecryptionCipherCtx 40 41 // pass in any extra data that was added during encryption with the 42 // encryption context's ExtraData() 43 ExtraData([]byte) error 44 45 // use before finalizing decryption to tell the library what the 46 // tag is expected to be 47 SetTag([]byte) error 48} 49 50type authEncryptionCipherCtx struct { 51 *encryptionCipherCtx 52} 53 54type authDecryptionCipherCtx struct { 55 *decryptionCipherCtx 56} 57 58func getGCMCipher(blocksize int) (*Cipher, error) { 59 var cipherptr *C.EVP_CIPHER 60 switch blocksize { 61 case 256: 62 cipherptr = C.EVP_aes_256_gcm() 63 case 192: 64 cipherptr = C.EVP_aes_192_gcm() 65 case 128: 66 cipherptr = C.EVP_aes_128_gcm() 67 default: 68 return nil, fmt.Errorf("unknown block size %d", blocksize) 69 } 70 return &Cipher{ptr: cipherptr}, nil 71} 72 73func NewGCMEncryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) ( 74 AuthenticatedEncryptionCipherCtx, error) { 75 cipher, err := getGCMCipher(blocksize) 76 if err != nil { 77 return nil, err 78 } 79 ctx, err := newEncryptionCipherCtx(cipher, e, key, nil) 80 if err != nil { 81 return nil, err 82 } 83 if len(iv) > 0 { 84 err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv)) 85 if err != nil { 86 return nil, fmt.Errorf("could not set IV len to %d: %s", 87 len(iv), err) 88 } 89 if 1 != C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, nil, 90 (*C.uchar)(&iv[0])) { 91 return nil, errors.New("failed to apply IV") 92 } 93 } 94 return &authEncryptionCipherCtx{encryptionCipherCtx: ctx}, nil 95} 96 97func NewGCMDecryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) ( 98 AuthenticatedDecryptionCipherCtx, error) { 99 cipher, err := getGCMCipher(blocksize) 100 if err != nil { 101 return nil, err 102 } 103 ctx, err := newDecryptionCipherCtx(cipher, e, key, nil) 104 if err != nil { 105 return nil, err 106 } 107 if len(iv) > 0 { 108 err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv)) 109 if err != nil { 110 return nil, fmt.Errorf("could not set IV len to %d: %s", 111 len(iv), err) 112 } 113 if 1 != C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, nil, 114 (*C.uchar)(&iv[0])) { 115 return nil, errors.New("failed to apply IV") 116 } 117 } 118 return &authDecryptionCipherCtx{decryptionCipherCtx: ctx}, nil 119} 120 121func (ctx *authEncryptionCipherCtx) ExtraData(aad []byte) error { 122 if aad == nil { 123 return nil 124 } 125 var outlen C.int 126 if 1 != C.EVP_EncryptUpdate(ctx.ctx, nil, &outlen, (*C.uchar)(&aad[0]), 127 C.int(len(aad))) { 128 return errors.New("failed to add additional authenticated data") 129 } 130 return nil 131} 132 133func (ctx *authDecryptionCipherCtx) ExtraData(aad []byte) error { 134 if aad == nil { 135 return nil 136 } 137 var outlen C.int 138 if 1 != C.EVP_DecryptUpdate(ctx.ctx, nil, &outlen, (*C.uchar)(&aad[0]), 139 C.int(len(aad))) { 140 return errors.New("failed to add additional authenticated data") 141 } 142 return nil 143} 144 145func (ctx *authEncryptionCipherCtx) GetTag() ([]byte, error) { 146 return ctx.getCtrlBytes(C.EVP_CTRL_GCM_GET_TAG, GCM_TAG_MAXLEN, 147 GCM_TAG_MAXLEN) 148} 149 150func (ctx *authDecryptionCipherCtx) SetTag(tag []byte) error { 151 return ctx.setCtrlBytes(C.EVP_CTRL_GCM_SET_TAG, len(tag), tag) 152} 153