core/riot/reference/RiotCrypt.c (287 lines of code) (raw):

/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See LICENSE in the project root. */ #include "include/RiotCrypt.h" #define RIOT_MAX_KDF_FIXED_SIZE RIOT_MAX_KDF_CONTEXT_LENGTH + \ RIOT_MAX_KDF_LABEL_LENGTH + 5 RIOT_STATUS RiotCrypt_SeedDRBG ( uint8_t *bytes, size_t size) { set_drbg_seed (bytes, size); return RIOT_SUCCESS; } RIOT_STATUS RiotCrypt_Kdf ( uint8_t *result, // OUT: Buffer to receive the derived bytes size_t resultSize, // IN: Capacity of the result buffer const uint8_t *source, // IN: Initial data for derivation size_t sourceSize, // IN: Size of the source data in bytes const uint8_t *context, // IN: Derivation context (may be NULL) size_t contextSize, // IN: Size of the context in bytes const uint8_t *label, // IN: Label for derivation (may be NULL) size_t labelSize, // IN: Size of the label in bytes uint32_t bytesToDerive // IN: Number of bytesto be produced ) { uint8_t fixed[RIOT_MAX_KDF_FIXED_SIZE]; size_t fixedSize = sizeof (fixed); uint32_t counter = 0; if ((contextSize > RIOT_MAX_KDF_CONTEXT_LENGTH) || (labelSize > RIOT_MAX_KDF_LABEL_LENGTH) || (bytesToDerive > resultSize) || (bytesToDerive % RIOT_KEY_LENGTH != 0)) { return RIOT_INVALID_PARAMETER; } fixedSize = RIOT_KDF_FIXED (fixed, fixedSize, context, contextSize, label, labelSize, bytesToDerive * 8); while (counter < (bytesToDerive / (RIOT_KEY_LENGTH))) { RIOT_KDF_SHA256 (result + (counter * (RIOT_KEY_LENGTH)), source, sourceSize, &counter, fixed, fixedSize); } return RIOT_SUCCESS; } typedef RIOT_SHA256_CONTEXT RIOT_HASH_CONTEXT; #define RiotCrypt_HashInit RIOT_SHA256_Init #define RiotCrypt_HashUpdate RIOT_SHA256_Update #define RiotCrypt_HashFinal RIOT_SHA256_Final RIOT_STATUS RiotCrypt_Hash ( uint8_t *result, // OUT: Buffer to receive the digest size_t resultSize, // IN: Capacity of the result buffer const void *data, // IN: Data to hash size_t dataSize // IN: Data size in bytes ) { RIOT_HASH_CONTEXT ctx; if (resultSize < RIOT_DIGEST_LENGTH) { return RIOT_INVALID_PARAMETER; } RiotCrypt_HashInit (&ctx); RiotCrypt_HashUpdate (&ctx, data, dataSize); RiotCrypt_HashFinal (&ctx, result); return RIOT_SUCCESS; } RIOT_STATUS RiotCrypt_Hash2 ( uint8_t *result, // OUT: Buffer to receive the digest size_t resultSize, // IN: Capacity of the result buffer const void *data1, // IN: 1st operand to hash size_t data1Size, // IN: 1st operand size in bytes const void *data2, // IN: 2nd operand to hash size_t data2Size // IN: 2nd operand size in bytes ) { RIOT_HASH_CONTEXT ctx; if (resultSize < RIOT_DIGEST_LENGTH) { return RIOT_INVALID_PARAMETER; } RiotCrypt_HashInit (&ctx); RiotCrypt_HashUpdate (&ctx, data1, data1Size); RiotCrypt_HashUpdate (&ctx, data2, data2Size); RiotCrypt_HashFinal (&ctx, result); return RIOT_SUCCESS; } typedef RIOT_HMAC_SHA256_CTX RIOT_HMAC_CONTEXT; #define RiotCrypt_HmacInit RIOT_HMAC_SHA256_Init #define RiotCrypt_HmacUpdate RIOT_HMAC_SHA256_Update #define RiotCrypt_HmacFinal RIOT_HMAC_SHA256_Final RIOT_STATUS RiotCrypt_Hmac ( uint8_t *result, // OUT: Buffer to receive the HMAC size_t resultCapacity, // IN: Capacity of the result buffer const void *data, // IN: Data to HMAC size_t dataSize, // IN: Data size in bytes const uint8_t *key, // IN: HMAK key size_t keySize // IN: HMAC key size in bytes ) { RIOT_HMAC_CONTEXT ctx; if ((resultCapacity < RIOT_HMAC_LENGTH) || (keySize != RIOT_HMAC_LENGTH)) { return RIOT_INVALID_PARAMETER; } RiotCrypt_HmacInit (&ctx, key, keySize); RiotCrypt_HmacUpdate (&ctx, data, dataSize); RiotCrypt_HmacFinal (&ctx, result); return RIOT_SUCCESS; } RIOT_STATUS RiotCrypt_Hmac2 ( uint8_t *result, // OUT: Buffer to receive the HMAK size_t resultCapacity, // IN: Capacity of the result buffer const void *data1, // IN: 1st operand to HMAC size_t data1Size, // IN: 1st operand size in bytes const void *data2, // IN: 2nd operand to HMAC size_t data2Size, // IN: 2nd operand size in bytes const uint8_t *key, // IN: HMAK key size_t keySize // IN: HMAC key size in bytes ) { RIOT_HMAC_CONTEXT ctx; if ((resultCapacity < RIOT_HMAC_LENGTH) || (keySize != RIOT_HMAC_LENGTH)) { return RIOT_INVALID_PARAMETER; } RiotCrypt_HmacInit (&ctx, key, keySize); RiotCrypt_HmacUpdate (&ctx, data1, data1Size); RiotCrypt_HmacUpdate (&ctx, data2, data2Size); RiotCrypt_HmacFinal (&ctx, result); return RIOT_SUCCESS; } RIOT_STATUS RiotCrypt_DeriveEccKey ( RIOT_ECC_PUBLIC *publicPart, // OUT: TODO RIOT_ECC_PRIVATE *privatePart, // OUT: TODO const void *srcData, // IN: TODO size_t srcDataSize // IN: TODO ) { if (srcDataSize > sizeof (bigval_t)) { return RIOT_INVALID_PARAMETER; } return RIOT_DeriveDsaKeyPair (publicPart, privatePart, (uint8_t*) srcData, srcDataSize); } void RiotCrypt_ExportEccPub ( const RIOT_ECC_PUBLIC *a, // IN: TODO uint8_t *b, // OUT: TODO size_t *s // OUT: TODO ) { *b++ = 0x04; BigValToBigInt (b, &a->x); b += RIOT_ECC_COORD_BYTES; BigValToBigInt (b, &a->y); if (s) { *s = 1 + 2 * RIOT_ECC_COORD_BYTES; } } RIOT_STATUS RiotCrypt_Sign ( RIOT_ECC_SIGNATURE *sig, // OUT: TODO const void *data, // IN: TODO size_t dataSize, // IN: TODO const RIOT_ECC_PRIVATE *key, // IN: TODO const struct rng_engine *rng // IN: TODO ) { size_t max_sig_len = RIOT_ECC_PRIVATE_BYTES * 4; uint8_t der_sig[max_sig_len]; int sig_len; int status; uint8_t digest[RIOT_DIGEST_LENGTH]; RiotCrypt_Hash (digest, sizeof (digest), data, dataSize); status = RIOT_DSASignDigest (digest, sizeof (digest), key, der_sig, max_sig_len, rng, &sig_len); if (status != 0) { return RIOT_FAILURE; } return RIOT_DSA_decode_signature (sig, der_sig, sig_len); } RIOT_STATUS RiotCrypt_SignDigest ( RIOT_ECC_SIGNATURE *sig, // OUT: TODO const uint8_t *digest, // IN: TODO size_t digestSize, // IN: TODO const RIOT_ECC_PRIVATE *key, // IN: TODO const struct rng_engine *rng // IN: TODO ) { size_t max_sig_len = RIOT_ECC_PRIVATE_BYTES * 4; uint8_t der_sig[max_sig_len]; int sig_len; int status; if (digestSize != RIOT_DIGEST_LENGTH) { return RIOT_INVALID_PARAMETER; } status = RIOT_DSASignDigest (digest, digestSize, key, der_sig, max_sig_len, rng, &sig_len); if (status != 0) { return RIOT_FAILURE; } return RIOT_DSA_decode_signature (sig, der_sig, sig_len); } RIOT_STATUS RiotCrypt_Verify ( const void *data, // IN: TODO size_t dataSize, // IN: TODO const RIOT_ECC_SIGNATURE *sig, // IN: TODO const RIOT_ECC_PUBLIC *key // IN: TODO ) { uint8_t digest[RIOT_DIGEST_LENGTH]; RiotCrypt_Hash (digest, sizeof (digest), data, dataSize); return RIOT_DSAVerifyDigest (digest, sizeof (digest), sig, key); } RIOT_STATUS RiotCrypt_VerifyDigest ( const uint8_t *digest, // IN: TODO size_t digestSize, // IN: TODO const RIOT_ECC_SIGNATURE *sig, // IN: TODO const RIOT_ECC_PUBLIC *key // IN: TODO ) { if (digestSize != RIOT_DIGEST_LENGTH) { return RIOT_INVALID_PARAMETER; } return RIOT_DSAVerifyDigest (digest, digestSize, sig, key); } #if USES_EPHEMERAL #define RIOT_LABEL_EXCHANGE "Exchange" RIOT_STATUS RiotCrypt_EccEncrypt ( uint8_t *result, // OUT: Buffer to receive encrypted data size_t resultCapacity, // IN: Capacity of the result buffer RIOT_ECC_PUBLIC *ephKey, // OUT: Ephemeral key to produce const void *data, // IN: Data to encrypt size_t dataSize, // IN: Data size in bytes const RIOT_ECC_PUBLIC *key, // IN: Encryption key const struct rng_engine *rng // IN: Random number generator engine ) { ecc_privatekey ephPriv; ecc_secret secret; uint8_t exchKey[RIOT_KEY_LENGTH]; RIOT_STATUS status; status = RIOT_GenerateDHKeyPair (ephKey, &ephPriv, rng); if (status != RIOT_SUCCESS) { return status; } status = RIOT_GenerateShareSecret ((RIOT_ECC_PUBLIC*) key, &ephPriv, &secret); if (status != RIOT_SUCCESS) { return status; } status = RiotCrypt_Kdf (exchKey, sizeof (exchKey), (uint8_t*) &secret, sizeof (secret), NULL, 0, (const uint8_t*) RIOT_LABEL_EXCHANGE, (sizeof (RIOT_LABEL_EXCHANGE) - 1), sizeof (exchKey)); if (status != RIOT_SUCCESS) { return status; } status = RiotCrypt_SymEncryptDecrypt (result, resultCapacity, data, dataSize, exchKey); return status; } RIOT_STATUS RiotCrypt_EccDecrypt ( uint8_t *result, // OUT: Buffer to receive decrypted data size_t resultCapacity, // IN: Capacity of the result buffer const void *data, // IN: Data to decrypt size_t dataSize, // IN: Data size in bytes RIOT_ECC_PUBLIC *ephKey, // IN: Ephemeral key to produce const RIOT_ECC_PRIVATE *key // IN: Decryption key ) { ecc_secret secret; uint8_t exchKey[RIOT_KEY_LENGTH]; RIOT_STATUS status; status = RIOT_GenerateShareSecret (ephKey, (RIOT_ECC_PRIVATE*) key, &secret); if (status != RIOT_SUCCESS) { return status; } status = RiotCrypt_Kdf (exchKey, sizeof (exchKey), (uint8_t*) &secret, sizeof (secret), NULL, 0, (const uint8_t*) RIOT_LABEL_EXCHANGE, (sizeof (RIOT_LABEL_EXCHANGE) - 1), sizeof (exchKey)); if (status != RIOT_SUCCESS) { return status; } status = RiotCrypt_SymEncryptDecrypt (result, resultCapacity, data, dataSize, exchKey); return status; } #endif RIOT_STATUS RiotCrypt_SymEncryptDecrypt ( void *outData, // OUT: Output data size_t outSize, // IN: Size of output data const void *inData, // IN: Input data size_t inSize, // IN: Size of input data uint8_t key[RIOT_SYM_KEY_LENGTH] // IN/OUT: Symmetric key & IV ) { uint8_t *iv = key + 16; aes128EncryptKey_t aesKey; if (outSize < inSize) { return RIOT_INVALID_PARAMETER; } RIOT_AES128_Enable (key, &aesKey); RIOT_AES_CTR_128 ((const aes128EncryptKey_t*) &aesKey, inData, outData, (uint32_t) inSize, iv); RIOT_AES128_Disable (&aesKey); return RIOT_SUCCESS; }