1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2001,2008 Oracle. All rights reserved. 5 * 6 * Some parts of this code originally written by Adam Stubblefield, 7 * -- astubble@rice.edu. 8 * 9 * $Id: aes_method.c,v 12.10 2008/01/08 20:58:08 bostic Exp $ 10 */ 11 12#include "db_config.h" 13 14#include "db_int.h" 15#include "dbinc/crypto.h" 16#include "dbinc/hmac.h" 17 18static void __aes_err __P((ENV *, int)); 19static int __aes_derivekeys __P((ENV *, DB_CIPHER *, u_int8_t *, size_t)); 20 21/* 22 * __aes_setup -- 23 * Setup AES functions. 24 * 25 * PUBLIC: int __aes_setup __P((ENV *, DB_CIPHER *)); 26 */ 27int 28__aes_setup(env, db_cipher) 29 ENV *env; 30 DB_CIPHER *db_cipher; 31{ 32 AES_CIPHER *aes_cipher; 33 int ret; 34 35 db_cipher->adj_size = __aes_adj_size; 36 db_cipher->close = __aes_close; 37 db_cipher->decrypt = __aes_decrypt; 38 db_cipher->encrypt = __aes_encrypt; 39 db_cipher->init = __aes_init; 40 if ((ret = __os_calloc(env, 1, sizeof(AES_CIPHER), &aes_cipher)) != 0) 41 return (ret); 42 db_cipher->data = aes_cipher; 43 return (0); 44} 45 46/* 47 * __aes_adj_size -- 48 * Given a size, return an addition amount needed to meet the 49 * "chunk" needs of the algorithm. 50 * 51 * PUBLIC: u_int __aes_adj_size __P((size_t)); 52 */ 53u_int 54__aes_adj_size(len) 55 size_t len; 56{ 57 if (len % DB_AES_CHUNK == 0) 58 return (0); 59 return (DB_AES_CHUNK - (u_int)(len % DB_AES_CHUNK)); 60} 61 62/* 63 * __aes_close -- 64 * Destroy the AES encryption instantiation. 65 * 66 * PUBLIC: int __aes_close __P((ENV *, void *)); 67 */ 68int 69__aes_close(env, data) 70 ENV *env; 71 void *data; 72{ 73 __os_free(env, data); 74 return (0); 75} 76 77/* 78 * __aes_decrypt -- 79 * Decrypt data with AES. 80 * 81 * PUBLIC: int __aes_decrypt __P((ENV *, void *, void *, 82 * PUBLIC: u_int8_t *, size_t)); 83 */ 84int 85__aes_decrypt(env, aes_data, iv, cipher, cipher_len) 86 ENV *env; 87 void *aes_data; 88 void *iv; 89 u_int8_t *cipher; 90 size_t cipher_len; 91{ 92 AES_CIPHER *aes; 93 cipherInstance c; 94 int ret; 95 96 aes = (AES_CIPHER *)aes_data; 97 if (iv == NULL || cipher == NULL) 98 return (EINVAL); 99 if ((cipher_len % DB_AES_CHUNK) != 0) 100 return (EINVAL); 101 /* 102 * Initialize the cipher 103 */ 104 if ((ret = __db_cipherInit(&c, MODE_CBC, iv)) < 0) { 105 __aes_err(env, ret); 106 return (EAGAIN); 107 } 108 109 /* Do the decryption */ 110 if ((ret = __db_blockDecrypt(&c, &aes->decrypt_ki, cipher, 111 cipher_len * 8, cipher)) < 0) { 112 __aes_err(env, ret); 113 return (EAGAIN); 114 } 115 return (0); 116} 117 118/* 119 * __aes_encrypt -- 120 * Encrypt data with AES. 121 * 122 * PUBLIC: int __aes_encrypt __P((ENV *, void *, void *, 123 * PUBLIC: u_int8_t *, size_t)); 124 */ 125int 126__aes_encrypt(env, aes_data, iv, data, data_len) 127 ENV *env; 128 void *aes_data; 129 void *iv; 130 u_int8_t *data; 131 size_t data_len; 132{ 133 AES_CIPHER *aes; 134 cipherInstance c; 135 u_int32_t tmp_iv[DB_IV_BYTES/4]; 136 int ret; 137 138 aes = (AES_CIPHER *)aes_data; 139 if (aes == NULL || data == NULL) 140 return (EINVAL); 141 if ((data_len % DB_AES_CHUNK) != 0) 142 return (EINVAL); 143 /* 144 * Generate the IV here. We store it in a tmp IV because 145 * the IV might be stored within the data we are encrypting 146 * and so we will copy it over to the given location after 147 * encryption is done. 148 * We don't do this outside of there because some encryption 149 * algorithms someone might add may not use IV's and we always 150 * want on here. 151 */ 152 if ((ret = __db_generate_iv(env, tmp_iv)) != 0) 153 return (ret); 154 155 /* 156 * Initialize the cipher 157 */ 158 if ((ret = __db_cipherInit(&c, MODE_CBC, (char *)tmp_iv)) < 0) { 159 __aes_err(env, ret); 160 return (EAGAIN); 161 } 162 163 /* Do the encryption */ 164 if ((ret = __db_blockEncrypt(&c, &aes->encrypt_ki, data, data_len * 8, 165 data)) < 0) { 166 __aes_err(env, ret); 167 return (EAGAIN); 168 } 169 memcpy(iv, tmp_iv, DB_IV_BYTES); 170 return (0); 171} 172 173/* 174 * __aes_init -- 175 * Initialize the AES encryption instantiation. 176 * 177 * PUBLIC: int __aes_init __P((ENV *, DB_CIPHER *)); 178 */ 179int 180__aes_init(env, db_cipher) 181 ENV *env; 182 DB_CIPHER *db_cipher; 183{ 184 DB_ENV *dbenv; 185 186 dbenv = env->dbenv; 187 188 return (__aes_derivekeys( 189 env, db_cipher, (u_int8_t *)dbenv->passwd, dbenv->passwd_len)); 190} 191 192static int 193__aes_derivekeys(env, db_cipher, passwd, plen) 194 ENV *env; 195 DB_CIPHER *db_cipher; 196 u_int8_t *passwd; 197 size_t plen; 198{ 199 AES_CIPHER *aes; 200 SHA1_CTX ctx; 201 int ret; 202 u_int32_t temp[DB_MAC_KEY/4]; 203 204 if (passwd == NULL) 205 return (EINVAL); 206 207 aes = (AES_CIPHER *)db_cipher->data; 208 209 /* Derive the crypto keys */ 210 __db_SHA1Init(&ctx); 211 __db_SHA1Update(&ctx, passwd, plen); 212 __db_SHA1Update(&ctx, (u_int8_t *)DB_ENC_MAGIC, strlen(DB_ENC_MAGIC)); 213 __db_SHA1Update(&ctx, passwd, plen); 214 __db_SHA1Final((u_int8_t *)temp, &ctx); 215 216 if ((ret = __db_makeKey(&aes->encrypt_ki, DIR_ENCRYPT, 217 DB_AES_KEYLEN, (char *)temp)) != TRUE) { 218 __aes_err(env, ret); 219 return (EAGAIN); 220 } 221 if ((ret = __db_makeKey(&aes->decrypt_ki, DIR_DECRYPT, 222 DB_AES_KEYLEN, (char *)temp)) != TRUE) { 223 __aes_err(env, ret); 224 return (EAGAIN); 225 } 226 return (0); 227} 228 229/* 230 * __aes_err -- 231 * Handle AES-specific errors. Codes and messages derived from 232 * rijndael/rijndael-api-fst.h. 233 */ 234static void 235__aes_err(env, err) 236 ENV *env; 237 int err; 238{ 239 char *errstr; 240 241 switch (err) { 242 case BAD_KEY_DIR: 243 errstr = "AES key direction is invalid"; 244 break; 245 case BAD_KEY_MAT: 246 errstr = "AES key material not of correct length"; 247 break; 248 case BAD_KEY_INSTANCE: 249 errstr = "AES key passwd not valid"; 250 break; 251 case BAD_CIPHER_MODE: 252 errstr = "AES cipher in wrong state (not initialized)"; 253 break; 254 case BAD_BLOCK_LENGTH: 255 errstr = "AES bad block length"; 256 break; 257 case BAD_CIPHER_INSTANCE: 258 errstr = "AES cipher instance is invalid"; 259 break; 260 case BAD_DATA: 261 errstr = "AES data contents are invalid"; 262 break; 263 case BAD_OTHER: 264 errstr = "AES unknown error"; 265 break; 266 default: 267 errstr = "AES error unrecognized"; 268 break; 269 } 270 __db_errx(env, errstr); 271 return; 272} 273