github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/accesscontrol/crypto/utils/aes.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package utils 18 19 import ( 20 "bytes" 21 "crypto/aes" 22 "crypto/cipher" 23 "crypto/rand" 24 "errors" 25 "fmt" 26 "io" 27 28 "github.com/hyperledger/fabric/core/crypto/primitives" 29 ) 30 31 const ( 32 // AESKeyLength is the default AES key length 33 AESKeyLength = 32 34 35 // NonceSize is the default NonceSize 36 NonceSize = 24 37 ) 38 39 // GenAESKey returns a random AES key of length AESKeyLength 40 func GenAESKey() ([]byte, error) { 41 return primitives.GetRandomBytes(AESKeyLength) 42 } 43 44 // PKCS7Padding pads as prescribed by the PKCS7 standard 45 func PKCS7Padding(src []byte) []byte { 46 padding := aes.BlockSize - len(src)%aes.BlockSize 47 padtext := bytes.Repeat([]byte{byte(padding)}, padding) 48 return append(src, padtext...) 49 } 50 51 // PKCS7UnPadding unpads as prescribed by the PKCS7 standard 52 func PKCS7UnPadding(src []byte) ([]byte, error) { 53 length := len(src) 54 unpadding := int(src[length-1]) 55 56 if unpadding > aes.BlockSize || unpadding == 0 { 57 return nil, fmt.Errorf("invalid padding") 58 } 59 60 pad := src[len(src)-unpadding:] 61 for i := 0; i < unpadding; i++ { 62 if pad[i] != byte(unpadding) { 63 return nil, fmt.Errorf("invalid padding") 64 } 65 } 66 67 return src[:(length - unpadding)], nil 68 } 69 70 // CBCEncrypt encrypts using CBC mode 71 func CBCEncrypt(key, s []byte) ([]byte, error) { 72 // CBC mode works on blocks so plaintexts may need to be padded to the 73 // next whole block. For an example of such padding, see 74 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll 75 // assume that the plaintext is already of the correct length. 76 if len(s)%aes.BlockSize != 0 { 77 return nil, errors.New("plaintext is not a multiple of the block size") 78 } 79 80 block, err := aes.NewCipher(key) 81 if err != nil { 82 return nil, err 83 } 84 85 // The IV needs to be unique, but not secure. Therefore it's common to 86 // include it at the beginning of the ciphertext. 87 ciphertext := make([]byte, aes.BlockSize+len(s)) 88 iv := ciphertext[:aes.BlockSize] 89 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 90 return nil, err 91 } 92 93 mode := cipher.NewCBCEncrypter(block, iv) 94 mode.CryptBlocks(ciphertext[aes.BlockSize:], s) 95 96 // It's important to remember that ciphertexts must be authenticated 97 // (i.e. by using crypto/hmac) as well as being encrypted in order to 98 // be secure. 99 return ciphertext, nil 100 } 101 102 // CBCDecrypt decrypts using CBC mode 103 func CBCDecrypt(key, src []byte) ([]byte, error) { 104 block, err := aes.NewCipher(key) 105 if err != nil { 106 return nil, err 107 } 108 109 // The IV needs to be unique, but not secure. Therefore it's common to 110 // include it at the beginning of the ciphertext. 111 if len(src) < aes.BlockSize { 112 return nil, errors.New("ciphertext too short") 113 } 114 iv := src[:aes.BlockSize] 115 src = src[aes.BlockSize:] 116 117 // CBC mode always works in whole blocks. 118 if len(src)%aes.BlockSize != 0 { 119 return nil, errors.New("ciphertext is not a multiple of the block size") 120 } 121 122 mode := cipher.NewCBCDecrypter(block, iv) 123 124 // CryptBlocks can work in-place if the two arguments are the same. 125 mode.CryptBlocks(src, src) 126 127 // If the original plaintext lengths are not a multiple of the block 128 // size, padding would have to be added when encrypting, which would be 129 // removed at this point. For an example, see 130 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's 131 // critical to note that ciphertexts must be authenticated (i.e. by 132 // using crypto/hmac) before being decrypted in order to avoid creating 133 // a padding oracle. 134 135 return src, nil 136 } 137 138 // CBCPKCS7Encrypt combines CBC encryption and PKCS7 padding 139 func CBCPKCS7Encrypt(key, src []byte) ([]byte, error) { 140 return CBCEncrypt(key, PKCS7Padding(src)) 141 } 142 143 // CBCPKCS7Decrypt combines CBC decryption and PKCS7 unpadding 144 func CBCPKCS7Decrypt(key, src []byte) ([]byte, error) { 145 pt, err := CBCDecrypt(key, src) 146 if err != nil { 147 return nil, err 148 } 149 150 original, err := PKCS7UnPadding(pt) 151 if err != nil { 152 return nil, err 153 } 154 155 return original, nil 156 }