github.com/searKing/golang/go@v1.2.117/crypto/aes/ctr.go (about) 1 // Copyright 2021 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package aes 6 7 import ( 8 "crypto/aes" 9 "crypto/cipher" 10 "crypto/rand" 11 "io" 12 13 "github.com/searKing/golang/go/crypto" 14 ) 15 16 func CTREncryptRandom(key, plaintext []byte) ([]byte, error) { 17 var iv = [aes.BlockSize]byte{} 18 if _, err := io.ReadFull(rand.Reader, iv[:]); err != nil { 19 return nil, err 20 } 21 return CBCEncrypt(key, plaintext, iv[:]) 22 } 23 24 func CTREncrypt(key, plaintext []byte, iv []byte) ([]byte, error) { 25 // Load your secret key from a safe place and reuse it across multiple 26 // NewCipher calls. (Obviously don't use this example key for anything 27 // real.) If you want to convert a passphrase to a key, use a suitable 28 // package like bcrypt or scrypt. 29 30 // CTR mode works on blocks so plaintexts may need to be padded to the 31 // next whole block. For an example of such padding, see 32 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. 33 paddingtext := crypto.PKCS7Padding(plaintext, aes.BlockSize) 34 35 block, err := aes.NewCipher(key) 36 if err != nil { 37 return nil, err 38 } 39 40 // The IV needs to be unique, but not secure. Therefore it's common to 41 // include it at the beginning of the ciphertext. 42 ciphertext := make([]byte, aes.BlockSize+len(paddingtext)) 43 if len(iv) < aes.BlockSize { 44 copy(ciphertext[:aes.BlockSize], iv[:]) 45 } else { 46 copy(ciphertext[:aes.BlockSize], iv[:aes.BlockSize]) 47 } 48 iv = ciphertext[:aes.BlockSize] 49 50 stream := cipher.NewCTR(block, iv) 51 stream.XORKeyStream(ciphertext[aes.BlockSize:], paddingtext) 52 53 // It's important to remember that ciphertexts must be authenticated 54 // (i.e. by using crypto/hmac) as well as being encrypted in order to 55 // be secure. 56 57 return ciphertext, nil 58 } 59 60 func CTRDecrypt(ciphertext, key []byte) ([]byte, error) { 61 // The IV needs to be unique, but not secure. Therefore it's common to 62 // include it at the beginning of the ciphertext. 63 if len(ciphertext) < aes.BlockSize { 64 panic("ciphertext too short") 65 } 66 iv := ciphertext[:aes.BlockSize] 67 ciphertext = ciphertext[aes.BlockSize:] 68 69 // CTR mode always works in whole blocks. 70 if len(ciphertext)%aes.BlockSize != 0 { 71 panic("ciphertext is not a multiple of the block size") 72 } 73 74 block, err := aes.NewCipher(key) 75 if err != nil { 76 return nil, err 77 } 78 79 stream := cipher.NewCTR(block, iv) 80 81 // XORKeyStream can work in-place if the two arguments are the same. 82 stream.XORKeyStream(ciphertext, ciphertext) 83 84 // If the original plaintext lengths are not a multiple of the block 85 // size, padding would have to be added when encrypting, which would be 86 // removed at this point. For an example, see 87 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's 88 // critical to note that ciphertexts must be authenticated (i.e. by 89 // using crypto/hmac) before being decrypted in order to avoid creating 90 // a padding oracle. 91 92 plaintext, err := crypto.PKCS7UnPadding(ciphertext, aes.BlockSize) 93 if err != nil { 94 return nil, err 95 } 96 return plaintext, nil 97 }