| 1 | |
| 2 | |
| 3 | * Minimal library implementation of AES in CFB mode
|
| 4 | *
|
| 5 | * Copyright 2023 Google LLC
|
| 6 |
|
| 7 |
|
| 8 | #include <crypto/aes.h>
|
| 9 | #include <crypto/utils.h>
|
| 10 | #include <linux/export.h>
|
| 11 | #include <linux/module.h>
|
| 12 |
|
| 13 | |
| 14 | * aescfb_encrypt - Perform AES-CFB encryption on a block of data
|
| 15 | *
|
| 16 | * @key: The AES-CFB key schedule
|
| 17 | * @dst: Pointer to the ciphertext output buffer
|
| 18 | * @src: Pointer the plaintext (may equal @dst for encryption in place)
|
| 19 | * @len: The size in bytes of the plaintext and ciphertext.
|
| 20 | * @iv: The initialization vector (IV) to use for this block of data
|
| 21 |
|
| 22 | void aescfb_encrypt(const struct aes_enckey *key, u8 *dst, const u8 *src,
|
| 23 | int len, const u8 iv[AES_BLOCK_SIZE])
|
| 24 | {
|
| 25 | u8 ks[AES_BLOCK_SIZE];
|
| 26 | const u8 *v = iv;
|
| 27 |
|
| 28 | while (len > 0) {
|
| 29 | aes_encrypt(key, ks, v);
|
| 30 | crypto_xor_cpy(dst, src, ks, min(len, AES_BLOCK_SIZE));
|
| 31 | v = dst;
|
| 32 |
|
| 33 | dst += AES_BLOCK_SIZE;
|
| 34 | src += AES_BLOCK_SIZE;
|
| 35 | len -= AES_BLOCK_SIZE;
|
| 36 | }
|
| 37 |
|
| 38 | memzero_explicit(ks, sizeof(ks));
|
| 39 | }
|
| 40 | EXPORT_SYMBOL(aescfb_encrypt);
|
| 41 |
|
| 42 | |
| 43 | * aescfb_decrypt - Perform AES-CFB decryption on a block of data
|
| 44 | *
|
| 45 | * @key: The AES-CFB key schedule
|
| 46 | * @dst: Pointer to the plaintext output buffer
|
| 47 | * @src: Pointer the ciphertext (may equal @dst for decryption in place)
|
| 48 | * @len: The size in bytes of the plaintext and ciphertext.
|
| 49 | * @iv: The initialization vector (IV) to use for this block of data
|
| 50 |
|
| 51 | void aescfb_decrypt(const struct aes_enckey *key, u8 *dst, const u8 *src,
|
| 52 | int len, const u8 iv[AES_BLOCK_SIZE])
|
| 53 | {
|
| 54 | u8 ks[2][AES_BLOCK_SIZE];
|
| 55 |
|
| 56 | aes_encrypt(key, ks[0], iv);
|
| 57 |
|
| 58 | for (int i = 0; len > 0; i ^= 1) {
|
| 59 | if (len > AES_BLOCK_SIZE)
|
| 60 | |
| 61 | * Generate the keystream for the next block before
|
| 62 | * performing the XOR, as that may update in place and
|
| 63 | * overwrite the ciphertext.
|
| 64 |
|
| 65 | aes_encrypt(key, ks[!i], src);
|
| 66 |
|
| 67 | crypto_xor_cpy(dst, src, ks[i], min(len, AES_BLOCK_SIZE));
|
| 68 |
|
| 69 | dst += AES_BLOCK_SIZE;
|
| 70 | src += AES_BLOCK_SIZE;
|
| 71 | len -= AES_BLOCK_SIZE;
|
| 72 | }
|
| 73 |
|
| 74 | memzero_explicit(ks, sizeof(ks));
|
| 75 | }
|
| 76 | EXPORT_SYMBOL(aescfb_decrypt);
|
| 77 |
|
| 78 | MODULE_DESCRIPTION("Generic AES-CFB library");
|
| 79 | MODULE_AUTHOR("Ard Biesheuvel <[email protected]>");
|
| 80 | MODULE_LICENSE("GPL");
|
| 81 |
|
| 82 | #ifdef CONFIG_CRYPTO_SELFTESTS
|
| 83 |
|
| 84 | |
| 85 | * Test code below. Vectors taken from crypto/testmgr.h
|
| 86 |
|
| 87 |
|
| 88 | static struct {
|
| 89 | u8 ptext[64] __nonstring;
|
| 90 | u8 ctext[64] __nonstring;
|
| 91 |
|
| 92 | u8 key[AES_MAX_KEY_SIZE] __nonstring;
|
| 93 | u8 iv[AES_BLOCK_SIZE] __nonstring;
|
| 94 |
|
| 95 | int klen;
|
| 96 | int len;
|
| 97 | } const aescfb_tv[] __initconst = {
|
| 98 | {
|
| 99 | .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
|
| 100 | "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
|
| 101 | .klen = 16,
|
| 102 | .iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
|
| 103 | "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
| 104 | .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
|
| 105 | "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
|
| 106 | "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
|
| 107 | "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
|
| 108 | "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
|
| 109 | "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
|
| 110 | "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
|
| 111 | "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
|
| 112 | .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20"
|
| 113 | "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a"
|
| 114 | "\xc8\xa6\x45\x37\xa0\xb3\xa9\x3f"
|
| 115 | "\xcd\xe3\xcd\xad\x9f\x1c\xe5\x8b"
|
| 116 | "\x26\x75\x1f\x67\xa3\xcb\xb1\x40"
|
| 117 | "\xb1\x80\x8c\xf1\x87\xa4\xf4\xdf"
|
| 118 | "\xc0\x4b\x05\x35\x7c\x5d\x1c\x0e"
|
| 119 | "\xea\xc4\xc6\x6f\x9f\xf7\xf2\xe6",
|
| 120 | .len = 64,
|
| 121 | }, {
|
| 122 | .key = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52"
|
| 123 | "\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
|
| 124 | "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
|
| 125 | .klen = 24,
|
| 126 | .iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
|
| 127 | "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
| 128 | .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
|
| 129 | "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
|
| 130 | "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
|
| 131 | "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
|
| 132 | "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
|
| 133 | "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
|
| 134 | "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
|
| 135 | "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
|
| 136 | .ctext = "\xcd\xc8\x0d\x6f\xdd\xf1\x8c\xab"
|
| 137 | "\x34\xc2\x59\x09\xc9\x9a\x41\x74"
|
| 138 | "\x67\xce\x7f\x7f\x81\x17\x36\x21"
|
| 139 | "\x96\x1a\x2b\x70\x17\x1d\x3d\x7a"
|
| 140 | "\x2e\x1e\x8a\x1d\xd5\x9b\x88\xb1"
|
| 141 | "\xc8\xe6\x0f\xed\x1e\xfa\xc4\xc9"
|
| 142 | "\xc0\x5f\x9f\x9c\xa9\x83\x4f\xa0"
|
| 143 | "\x42\xae\x8f\xba\x58\x4b\x09\xff",
|
| 144 | .len = 64,
|
| 145 | }, {
|
| 146 | .key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
|
| 147 | "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
|
| 148 | "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
|
| 149 | "\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
|
| 150 | .klen = 32,
|
| 151 | .iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
|
| 152 | "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
| 153 | .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
|
| 154 | "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
|
| 155 | "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
|
| 156 | "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
|
| 157 | "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
|
| 158 | "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
|
| 159 | "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
|
| 160 | "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
|
| 161 | .ctext = "\xdc\x7e\x84\xbf\xda\x79\x16\x4b"
|
| 162 | "\x7e\xcd\x84\x86\x98\x5d\x38\x60"
|
| 163 | "\x39\xff\xed\x14\x3b\x28\xb1\xc8"
|
| 164 | "\x32\x11\x3c\x63\x31\xe5\x40\x7b"
|
| 165 | "\xdf\x10\x13\x24\x15\xe5\x4b\x92"
|
| 166 | "\xa1\x3e\xd0\xa8\x26\x7a\xe2\xf9"
|
| 167 | "\x75\xa3\x85\x74\x1a\xb9\xce\xf8"
|
| 168 | "\x20\x31\x62\x3d\x55\xb1\xe4\x71",
|
| 169 | .len = 64,
|
| 170 | }, {
|
| 171 | .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
|
| 172 | "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
|
| 173 | .klen = 16,
|
| 174 | .iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
|
| 175 | "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
| 176 | .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
|
| 177 | "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
|
| 178 | "\xae",
|
| 179 | .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20"
|
| 180 | "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a"
|
| 181 | "\xc8",
|
| 182 | .len = 17,
|
| 183 | }, {
|
| 184 | .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
|
| 185 | "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
|
| 186 | .klen = 16,
|
| 187 | .iv = "\x00\x01\x02\x03\x04\x05\x06\x07"
|
| 188 | "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
| 189 | .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f",
|
| 190 | .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad",
|
| 191 | .len = 7,
|
| 192 | },
|
| 193 | };
|
| 194 |
|
| 195 | static int __init libaescfb_init(void)
|
| 196 | {
|
| 197 | for (int i = 0; i < ARRAY_SIZE(aescfb_tv); i++) {
|
| 198 | struct aes_enckey key;
|
| 199 | u8 buf[64];
|
| 200 |
|
| 201 | if (aes_prepareenckey(&key, aescfb_tv[i].key, aescfb_tv[i].klen)) {
|
| 202 | pr_err("aes_prepareenckey() failed on vector %d\n", i);
|
| 203 | return -ENODEV;
|
| 204 | }
|
| 205 |
|
| 206 | aescfb_encrypt(&key, buf, aescfb_tv[i].ptext, aescfb_tv[i].len,
|
| 207 | aescfb_tv[i].iv);
|
| 208 | if (memcmp(buf, aescfb_tv[i].ctext, aescfb_tv[i].len)) {
|
| 209 | pr_err("aescfb_encrypt() #1 failed on vector %d\n", i);
|
| 210 | return -ENODEV;
|
| 211 | }
|
| 212 |
|
| 213 |
|
| 214 | aescfb_decrypt(&key, buf, buf, aescfb_tv[i].len, aescfb_tv[i].iv);
|
| 215 | if (memcmp(buf, aescfb_tv[i].ptext, aescfb_tv[i].len)) {
|
| 216 | pr_err("aescfb_decrypt() failed on vector %d\n", i);
|
| 217 | return -ENODEV;
|
| 218 | }
|
| 219 |
|
| 220 |
|
| 221 | aescfb_encrypt(&key, buf, buf, aescfb_tv[i].len, aescfb_tv[i].iv);
|
| 222 | if (memcmp(buf, aescfb_tv[i].ctext, aescfb_tv[i].len)) {
|
| 223 | pr_err("aescfb_encrypt() #2 failed on vector %d\n", i);
|
| 224 |
|
| 225 | return -ENODEV;
|
| 226 | }
|
| 227 |
|
| 228 | }
|
| 229 | return 0;
|
| 230 | }
|
| 231 | module_init(libaescfb_init);
|
| 232 |
|
| 233 | static void __exit libaescfb_exit(void)
|
| 234 | {
|
| 235 | }
|
| 236 | module_exit(libaescfb_exit);
|
| 237 | #endif
|