| 1 | #include <stdint.h> |
| 2 | #include <stdlib.h> |
| 3 | |
| 4 | #include "crypto_aes.h" |
| 5 | #include "insecure_memzero.h" |
| 6 | #include "sysendian.h" |
| 7 | |
| 8 | #include "crypto_aesctr.h" |
| 9 | |
| 10 | struct crypto_aesctr { |
| 11 | const struct crypto_aes_key * key; |
| 12 | uint64_t nonce; |
| 13 | uint64_t bytectr; |
| 14 | uint8_t buf[16]; |
| 15 | }; |
| 16 | |
| 17 | /** |
| 18 | * crypto_aesctr_init(key, nonce): |
| 19 | * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided |
| 20 | * expanded key and nonce. The key provided must remain valid for the |
| 21 | * lifetime of the stream. |
| 22 | */ |
| 23 | struct crypto_aesctr * |
| 24 | crypto_aesctr_init(const struct crypto_aes_key * key, uint64_t nonce) |
| 25 | { |
| 26 | struct crypto_aesctr * stream; |
| 27 | |
| 28 | /* Allocate memory. */ |
| 29 | if ((stream = malloc(sizeof(struct crypto_aesctr))) == NULL) |
| 30 | goto err0; |
| 31 | |
| 32 | /* Initialize values. */ |
| 33 | stream->key = key; |
| 34 | stream->nonce = nonce; |
| 35 | stream->bytectr = 0; |
| 36 | |
| 37 | /* Success! */ |
| 38 | return (stream); |
| 39 | |
| 40 | err0: |
| 41 | /* Failure! */ |
| 42 | return (NULL); |
| 43 | } |
| 44 | |
| 45 | /** |
| 46 | * crypto_aesctr_stream(stream, inbuf, outbuf, buflen): |
| 47 | * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with |
| 48 | * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers |
| 49 | * ${inbuf} and ${outbuf} overlap, they must be identical. |
| 50 | */ |
| 51 | void |
| 52 | crypto_aesctr_stream(struct crypto_aesctr * stream, const uint8_t * inbuf, |
| 53 | uint8_t * outbuf, size_t buflen) |
| 54 | { |
| 55 | uint8_t pblk[16]; |
| 56 | size_t pos; |
| 57 | int bytemod; |
| 58 | |
| 59 | for (pos = 0; pos < buflen; pos++) { |
| 60 | /* How far through the buffer are we? */ |
| 61 | bytemod = stream->bytectr % 16; |
| 62 | |
| 63 | /* Generate a block of cipherstream if needed. */ |
| 64 | if (bytemod == 0) { |
| 65 | be64enc(pblk, stream->nonce); |
| 66 | be64enc(pblk + 8, stream->bytectr / 16); |
| 67 | crypto_aes_encrypt_block(pblk, stream->buf, |
| 68 | stream->key); |
| 69 | } |
| 70 | |
| 71 | /* Encrypt a byte. */ |
| 72 | outbuf[pos] = inbuf[pos] ^ stream->buf[bytemod]; |
| 73 | |
| 74 | /* Move to the next byte of cipherstream. */ |
| 75 | stream->bytectr += 1; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | /** |
| 80 | * crypto_aesctr_free(stream): |
| 81 | * Free the provided stream object. |
| 82 | */ |
| 83 | void |
| 84 | crypto_aesctr_free(struct crypto_aesctr * stream) |
| 85 | { |
| 86 | |
| 87 | /* Behave consistently with free(NULL). */ |
| 88 | if (stream == NULL) |
| 89 | return; |
| 90 | |
| 91 | /* Zero potentially sensitive information. */ |
| 92 | insecure_memzero(stream, sizeof(struct crypto_aesctr)); |
| 93 | |
| 94 | /* Free the stream. */ |
| 95 | free(stream); |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * crypto_aesctr_buf(key, nonce, inbuf, outbuf, buflen): |
| 100 | * Equivalent to _init(key, nonce); _stream(inbuf, outbuf, buflen); _free(). |
| 101 | */ |
| 102 | void |
| 103 | crypto_aesctr_buf(const struct crypto_aes_key * key, uint64_t nonce, |
| 104 | const uint8_t * inbuf, uint8_t * outbuf, size_t buflen) |
| 105 | { |
| 106 | struct crypto_aesctr stream_rec; |
| 107 | struct crypto_aesctr * stream = &stream_rec; |
| 108 | |
| 109 | /* Initialize values. */ |
| 110 | stream->key = key; |
| 111 | stream->nonce = nonce; |
| 112 | stream->bytectr = 0; |
| 113 | |
| 114 | /* Perform the encryption. */ |
| 115 | crypto_aesctr_stream(stream, inbuf, outbuf, buflen); |
| 116 | |
| 117 | /* Zero potentially sensitive information. */ |
| 118 | insecure_memzero(stream, sizeof(struct crypto_aesctr)); |
| 119 | } |