/* Generates an key derived from a password and salt using a memory hard * algorithm. * Implements RFC 7914: scrypt PBKDF. * * output The derived key. * passwd The password to derive key from. * passLen The length of the password. * salt The key specific data. * saltLen The length of the salt data. * cost The CPU/memory cost parameter. Range: 1..(128*r/8-1) * (Iterations = 2^cost) * blockSize The number of 128 byte octets in a working block. * parallel The number of parallel mix operations to perform. * (Note: this implementation does not use threads.) * dkLen The length of the derived key in bytes. * returns BAD_FUNC_ARG when: parallel not 1, blockSize is too large for cost. */ int wc_scrypt(byte* output, const byte* passwd, int passLen, const byte* salt, int saltLen, int cost, int blockSize, int parallel, int dkLen) { int ret = 0; int i; byte* v = NULL; byte* y = NULL; byte* blocks = NULL; word32 blocksSz; word32 bSz; if (blockSize > 8) return BAD_FUNC_ARG; if (cost < 1 || cost >= 128 * blockSize / 8) return BAD_FUNC_ARG; bSz = 128 * blockSize; blocksSz = bSz * parallel; blocks = XMALLOC(blocksSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (blocks == NULL) goto end; /* Temporary for scryptROMix. */ v = XMALLOC((1 << cost) * bSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (v == NULL) goto end; /* Temporary for scryptBlockMix. */ y = XMALLOC(blockSize * 128, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (y == NULL) goto end; /* Step 1. */ ret = wc_PBKDF2(blocks, passwd, passLen, salt, saltLen, 1, blocksSz, SHA256); if (ret != 0) goto end; /* Step 2. */ for (i = 0; i < parallel; i++) scryptROMix(blocks + i * bSz, v, y, blockSize, 1 << cost); /* Step 3. */ ret = wc_PBKDF2(output, passwd, passLen, blocks, blocksSz, 1, dkLen, SHA256); end: if (blocks != NULL) XFREE(blocks, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (v != NULL) XFREE(v, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (y != NULL) XFREE(y, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; }
/* * makes a cyptographically secure key by stretching a user entered pwdKey */ int wolfsslGenKey(RNG* rng, byte* pwdKey, int size, byte* salt, int pad) { int ret; /* return variable */ /* randomly generates salt */ ret = wc_RNG_GenerateBlock(rng, salt, SALT_SIZE-1); if (ret != 0) return ret; /* set first value of salt to let us know * if message has padding or not */ if (pad == 0) salt[0] = 0; /* stretches pwdKey */ ret = (int) wc_PBKDF2(pwdKey, pwdKey, (int) strlen((const char*)pwdKey), salt, SALT_SIZE, 4096, size, SHA256); if (ret != 0) return ret; return 0; }
/* * Makes a cryptographically secure key by stretching a user entered key */ int GenerateKey(RNG* rng, byte* key, int size, byte* salt, int pad) { int ret; ret = wc_RNG_GenerateBlock(rng, salt, SALT_SIZE); if (ret != 0) return -1020; if (pad == 0) salt[0] = 0; /* stretches key */ ret = wc_PBKDF2(key, key, strlen((const char*)key), salt, SALT_SIZE, 4096, size, WC_SHA256); if (ret != 0) return -1030; return 0; }
/* * Makes a cryptographically secure key by stretMDMching a user entered key */ int GenerateKey(RNG* rng, byte* key, int size, byte* salt, int pad) { int ret; ret = wc_RNG_GenerateBlock(rng, salt, SALT_SIZE-1); if (ret != 0) return -1020; if (pad == 0) /* sets first value of salt to check if the */ salt[0] = 0; /* message is padded */ /* stretches key */ ret = wc_PBKDF2(key, key, strlen((const char*)key), salt, SALT_SIZE, 4096, size, SHA256); if (ret != 0) return -1030; return 0; }
/* * Decrypts a file using AES */ int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile) { RNG rng; byte iv[AES_BLOCK_SIZE]; byte* input; byte* output; byte salt[SALT_SIZE] = {0}; int i = 0; int ret = 0; int length; int aSize; fseek(inFile, 0, SEEK_END); length = ftell(inFile); fseek(inFile, 0, SEEK_SET); aSize = length; input = malloc(aSize); output = malloc(aSize); wc_InitRng(&rng); /* reads from inFile and writes whatever is there to the input array */ ret = fread(input, 1, length, inFile); if (ret == 0) { printf("Input file does not exist.\n"); return -1010; } for (i = 0; i < SALT_SIZE; i++) { /* finds salt from input message */ salt[i] = input[i]; } for (i = SALT_SIZE; i < AES_BLOCK_SIZE + SALT_SIZE; i++) { /* finds iv from input message */ iv[i - SALT_SIZE] = input[i]; } /* replicates old key if keys match */ ret = wc_PBKDF2(key, key, strlen((const char*)key), salt, SALT_SIZE, 4096, size, WC_SHA256); if (ret != 0) return -1050; /* sets key */ ret = wc_AesSetKey(aes, key, AES_BLOCK_SIZE, iv, AES_DECRYPTION); if (ret != 0) return -1002; /* change length to remove salt/iv block from being decrypted */ length -= (AES_BLOCK_SIZE + SALT_SIZE); for (i = 0; i < length; i++) { /* shifts message: ignores salt/iv on message*/ input[i] = input[i + (AES_BLOCK_SIZE + SALT_SIZE)]; } /* decrypts the message to output based on input length + padding*/ ret = wc_AesCbcDecrypt(aes, output, input, length); if (ret != 0) return -1006; if (salt[0] != 0) { /* reduces length based on number of padded elements */ length -= output[length-1]; } /* writes output to the outFile based on shortened length */ fwrite(output, 1, length, outFile); /* closes the opened files and frees the memory*/ memset(input, 0, aSize); memset(output, 0, aSize); memset(key, 0, size); free(input); free(output); free(key); fclose(inFile); fclose(outFile); wc_FreeRng(&rng); return 0; }