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 15// +build !openssl_pre_1.0 16 17package openssl 18 19// #include <openssl/evp.h> 20import "C" 21 22import ( 23 "errors" 24 "fmt" 25) 26 27type AuthenticatedEncryptionCipherCtx interface { 28 EncryptionCipherCtx 29 30 // data passed in to ExtraData() is part of the final output; it is 31 // not encrypted itself, but is part of the authenticated data. when 32 // decrypting or authenticating, pass back with the decryption 33 // context's ExtraData() 34 ExtraData([]byte) error 35 36 // use after finalizing encryption to get the authenticating tag 37 GetTag() ([]byte, error) 38} 39 40type AuthenticatedDecryptionCipherCtx interface { 41 DecryptionCipherCtx 42 43 // pass in any extra data that was added during encryption with the 44 // encryption context's ExtraData() 45 ExtraData([]byte) error 46 47 // use before finalizing decryption to tell the library what the 48 // tag is expected to be 49 SetTag([]byte) error 50} 51 52type authEncryptionCipherCtx struct { 53 *encryptionCipherCtx 54} 55 56type authDecryptionCipherCtx struct { 57 *decryptionCipherCtx 58} 59 60func getGCMCipher(blocksize int) (*Cipher, error) { 61 var cipherptr *C.EVP_CIPHER 62 switch blocksize { 63 case 256: 64 cipherptr = C.EVP_aes_256_gcm() 65 case 192: 66 cipherptr = C.EVP_aes_192_gcm() 67 case 128: 68 cipherptr = C.EVP_aes_128_gcm() 69 default: 70 return nil, fmt.Errorf("unknown block size %d", blocksize) 71 } 72 return &Cipher{ptr: cipherptr}, nil 73} 74 75func NewGCMEncryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) ( 76 AuthenticatedEncryptionCipherCtx, error) { 77 cipher, err := getGCMCipher(blocksize) 78 if err != nil { 79 return nil, err 80 } 81 ctx, err := newEncryptionCipherCtx(cipher, e, key, nil) 82 if err != nil { 83 return nil, err 84 } 85 if len(iv) > 0 { 86 err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv)) 87 if err != nil { 88 return nil, fmt.Errorf("could not set IV len to %d: %s", 89 len(iv), err) 90 } 91 if 1 != C.EVP_EncryptInit_ex(ctx.ctx, nil, nil, nil, 92 (*C.uchar)(&iv[0])) { 93 return nil, errors.New("failed to apply IV") 94 } 95 } 96 return &authEncryptionCipherCtx{encryptionCipherCtx: ctx}, nil 97} 98 99func NewGCMDecryptionCipherCtx(blocksize int, e *Engine, key, iv []byte) ( 100 AuthenticatedDecryptionCipherCtx, error) { 101 cipher, err := getGCMCipher(blocksize) 102 if err != nil { 103 return nil, err 104 } 105 ctx, err := newDecryptionCipherCtx(cipher, e, key, nil) 106 if err != nil { 107 return nil, err 108 } 109 if len(iv) > 0 { 110 err := ctx.setCtrl(C.EVP_CTRL_GCM_SET_IVLEN, len(iv)) 111 if err != nil { 112 return nil, fmt.Errorf("could not set IV len to %d: %s", 113 len(iv), err) 114 } 115 if 1 != C.EVP_DecryptInit_ex(ctx.ctx, nil, nil, nil, 116 (*C.uchar)(&iv[0])) { 117 return nil, errors.New("failed to apply IV") 118 } 119 } 120 return &authDecryptionCipherCtx{decryptionCipherCtx: ctx}, nil 121} 122 123func (ctx *authEncryptionCipherCtx) ExtraData(aad []byte) error { 124 if aad == nil { 125 return nil 126 } 127 var outlen C.int 128 if 1 != C.EVP_EncryptUpdate(ctx.ctx, nil, &outlen, (*C.uchar)(&aad[0]), 129 C.int(len(aad))) { 130 return errors.New("failed to add additional authenticated data") 131 } 132 return nil 133} 134 135func (ctx *authDecryptionCipherCtx) ExtraData(aad []byte) error { 136 if aad == nil { 137 return nil 138 } 139 var outlen C.int 140 if 1 != C.EVP_DecryptUpdate(ctx.ctx, nil, &outlen, (*C.uchar)(&aad[0]), 141 C.int(len(aad))) { 142 return errors.New("failed to add additional authenticated data") 143 } 144 return nil 145} 146 147func (ctx *authEncryptionCipherCtx) GetTag() ([]byte, error) { 148 return ctx.getCtrlBytes(C.EVP_CTRL_GCM_GET_TAG, GCM_TAG_MAXLEN, 149 GCM_TAG_MAXLEN) 150} 151 152func (ctx *authDecryptionCipherCtx) SetTag(tag []byte) error { 153 return ctx.setCtrlBytes(C.EVP_CTRL_GCM_SET_TAG, len(tag), tag) 154} 155