error_t dhGenerateKeyPair(DhContext *context, const PrngAlgo *prngAlgo, void *prngContext) { error_t error; uint_t k; //Debug message TRACE_DEBUG("Generating Diffie-Hellman key pair...\r\n"); //Get the length in bits of the prime p k = mpiGetBitLength(&context->params.p); //Ensure the length is valid if(!k) return ERROR_INVALID_PARAMETER; //The private value shall be randomly generated error = mpiRand(&context->xa, k, prngAlgo, prngContext); //Any error to report? if(error) return error; //The private value shall be less than p if(mpiComp(&context->xa, &context->params.p) >= 0) { //Shift value to the right error = mpiShiftRight(&context->xa, 1); //Any error to report? if(error) return error; } //Debug message TRACE_DEBUG(" Private value:\r\n"); TRACE_DEBUG_MPI(" ", &context->xa); //Calculate the corresponding public value (ya = g ^ xa mod p) error = mpiExpMod(&context->ya, &context->params.g, &context->xa, &context->params.p); //Any error to report? if(error) return error; //Debug message TRACE_DEBUG(" Public value:\r\n"); TRACE_DEBUG_MPI(" ", &context->ya); //Check public value error = dhCheckPublicKey(&context->params, &context->ya); //Weak public value? if(error) return error; //Public value successfully generated return NO_ERROR; }
error_t ecLoadDomainParameters(EcDomainParameters *params, const EcCurveInfo *curveInfo) { error_t error; //Debug message TRACE_DEBUG("Loading %s EC domain parameters...\r\n", curveInfo->name); //Curve type params->type = curveInfo->type; //Import prime modulus MPI_CHECK(mpiReadRaw(¶ms->p, curveInfo->p, curveInfo->pLen)); //Import parameter a MPI_CHECK(mpiReadRaw(¶ms->a, curveInfo->a, curveInfo->aLen)); //Import parameter b MPI_CHECK(mpiReadRaw(¶ms->b, curveInfo->b, curveInfo->bLen)); //Import the x-coordinate of the base point G MPI_CHECK(mpiReadRaw(¶ms->g.x, curveInfo->gx, curveInfo->gxLen)); //Import the y-coordinate of the base point G MPI_CHECK(mpiReadRaw(¶ms->g.y, curveInfo->gy, curveInfo->gyLen)); //Import base point order q MPI_CHECK(mpiReadRaw(¶ms->q, curveInfo->q, curveInfo->qLen)); //Normalize base point G MPI_CHECK(mpiSetValue(¶ms->g.z, 1)); //Fast modular reduction params->mod = curveInfo->mod; //Debug message TRACE_DEBUG(" p:\r\n"); TRACE_DEBUG_MPI(" ", ¶ms->p); TRACE_DEBUG(" a:\r\n"); TRACE_DEBUG_MPI(" ", ¶ms->a); TRACE_DEBUG(" b:\r\n"); TRACE_DEBUG_MPI(" ", ¶ms->b); TRACE_DEBUG(" Gx:\r\n"); TRACE_DEBUG_MPI(" ", ¶ms->g.x); TRACE_DEBUG(" Gy:\r\n"); TRACE_DEBUG_MPI(" ", ¶ms->g.y); TRACE_DEBUG(" q:\r\n"); TRACE_DEBUG_MPI(" ", ¶ms->q); end: //Return status code return error; }
error_t pemReadDhParameters(const char_t *input, size_t length, DhParameters *params) { error_t error; size_t i; size_t j; int_t k; char_t *buffer; const uint8_t *data; Asn1Tag tag; //Check parameters if(input == NULL && length != 0) return ERROR_INVALID_PARAMETER; if(params == NULL) return ERROR_INVALID_PARAMETER; //Search for the beginning tag k = pemSearchTag(input, length, "-----BEGIN DH PARAMETERS-----", 29); //Failed to find the specified tag? if(k < 0) return ERROR_INVALID_SYNTAX; //Advance the pointer over the tag input += k + 29; length -= k + 29; //Search for the end tag k = pemSearchTag(input, length, "-----END DH PARAMETERS-----", 27); //Invalid PEM file? if(k <= 0) return ERROR_INVALID_SYNTAX; //Length of the PEM structure length = k; //Allocate a memory buffer to hold the decoded data buffer = osMemAlloc(length); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Copy the contents of the PEM structure memcpy(buffer, input, length); //Remove carriage returns and line feeds for(i = 0, j = 0; i < length; i++) { if(buffer[i] != '\r' && buffer[i] != '\n') buffer[j++] = buffer[i]; } //Start of exception handling block do { //The PEM file is Base64 encoded... error = base64Decode(buffer, j, buffer, &length); //Failed to decode the file? if(error) break; //Point to the resulting ASN.1 structure data = (uint8_t *) buffer; //Display ASN.1 structure error = asn1DumpObject(data, length, 0); //Any error to report? if(error) break; //The Diffie-Hellman parameters are encapsulated within a sequence error = asn1ReadTag(data, length, &tag); //Failed to decode ASN.1 tag? if(error) break; //Enforce encoding, type and class error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE); //The tag does not match the criteria? if(error) break; //Point to the first field of the sequence data = tag.value; length = tag.length; //Read the prime modulus error = asn1ReadTag(data, length, &tag); //Failed to decode ASN.1 tag? if(error) break; //Enforce encoding, type and class error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER); //The tag does not match the criteria? if(error) break; //Convert the prime modulus to a multiple precision integer error = mpiReadRaw(¶ms->p, tag.value, tag.length); //Any error to report? if(error) break; //Point to the next field data += tag.totalLength; length -= tag.totalLength; //Read the generator error = asn1ReadTag(data, length, &tag); //Failed to decode ASN.1 tag? if(error) break; //Enforce encoding, type and class error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_INTEGER); //The tag does not match the criteria? if(error) break; //Convert the generator to a multiple precision integer error = mpiReadRaw(¶ms->g, tag.value, tag.length); //Any error to report? if(error) break; //Debug message TRACE_DEBUG("Diffie-Hellman parameters:\r\n"); TRACE_DEBUG(" Prime modulus:\r\n"); TRACE_DEBUG_MPI(" ", ¶ms->p); TRACE_DEBUG(" Generator:\r\n"); TRACE_DEBUG_MPI(" ", ¶ms->g); //End of exception handling block } while(0); //Release previously allocated memory osMemFree(buffer); //Clean up side effects if necessary if(error) dhFreeParameters(params); //Return status code return error; }
error_t rsassaPkcs1v15Verify(const RsaPublicKey *key, const HashAlgo *hash, const uint8_t *digest, const uint8_t *signature, size_t signatureLength) { error_t error; uint_t k; uint8_t *em; const uint8_t *oid; size_t oidLength; const uint8_t *d; size_t dLength; Mpi s; Mpi m; //Check parameters if(key == NULL || hash == NULL || digest == NULL || signature == NULL) return ERROR_INVALID_PARAMETER; //Debug message TRACE_DEBUG("RSA PKCS #1 v1.5 signature verification...\r\n"); TRACE_DEBUG(" Modulus:\r\n"); TRACE_DEBUG_MPI(" ", &key->n); TRACE_DEBUG(" Public exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->e); TRACE_DEBUG(" Message digest:\r\n"); TRACE_DEBUG_ARRAY(" ", digest, hash->digestSize); TRACE_DEBUG(" Signature:\r\n"); TRACE_DEBUG_ARRAY(" ", signature, signatureLength); //Initialize multiple-precision integers mpiInit(&s); mpiInit(&m); //Get the length in octets of the modulus n k = mpiGetByteLength(&key->n); //Check the length of the signature if(signatureLength != k) return ERROR_INVALID_LENGTH; //Allocate a memory buffer to hold the encoded message em = osAllocMem(k); //Failed to allocate memory? if(!em) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Convert the signature to an integer signature representative s error = mpiReadRaw(&s, signature, signatureLength); //Conversion failed? if(error) break; //Apply the RSAVP1 verification primitive error = rsavp1(key, &s, &m); //Any error to report? if(error) break; //Convert the message representative m to an encoded message EM of length k octets error = mpiWriteRaw(&m, em, k); //Conversion failed? if(error) break; //Debug message TRACE_DEBUG(" Encoded message\r\n"); TRACE_DEBUG_ARRAY(" ", em, k); //Parse the encoded message EM error = emsaPkcs1v15Decode(em, k, &oid, &oidLength, &d, &dLength); //Any error to report? if(error) break; //Assume an error... error = ERROR_INVALID_SIGNATURE_ALGO; //Ensure the hash algorithm identifier matches the OID if(oidComp(oid, oidLength, hash->oid, hash->oidSize)) break; //Check the length of the digest if(dLength != hash->digestSize) break; //Compare the message digest error = memcmp(digest, d, dLength) ? ERROR_INVALID_SIGNATURE : NO_ERROR; //End of exception handling block } while(0); //Release multiple precision integers mpiFree(&s); mpiFree(&m); //Free previously allocated memory osFreeMem(em); //Return status code return error; }
error_t rsassaPkcs1v15Sign(const RsaPrivateKey *key, const HashAlgo *hash, const uint8_t *digest, uint8_t *signature, size_t *signatureLength) { error_t error; uint_t k; uint8_t *em; Mpi m; Mpi s; //Check parameters if(key == NULL || hash == NULL || digest == NULL) return ERROR_INVALID_PARAMETER; if(signature == NULL || signatureLength == NULL) return ERROR_INVALID_PARAMETER; //Debug message TRACE_DEBUG("RSA PKCS #1 v1.5 signature generation...\r\n"); TRACE_DEBUG(" Modulus:\r\n"); TRACE_DEBUG_MPI(" ", &key->n); TRACE_DEBUG(" Public exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->e); TRACE_DEBUG(" Private exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->d); TRACE_DEBUG(" Prime 1:\r\n"); TRACE_DEBUG_MPI(" ", &key->p); TRACE_DEBUG(" Prime 2:\r\n"); TRACE_DEBUG_MPI(" ", &key->q); TRACE_DEBUG(" Prime exponent 1:\r\n"); TRACE_DEBUG_MPI(" ", &key->dp); TRACE_DEBUG(" Prime exponent 2:\r\n"); TRACE_DEBUG_MPI(" ", &key->dq); TRACE_DEBUG(" Coefficient:\r\n"); TRACE_DEBUG_MPI(" ", &key->qinv); TRACE_DEBUG(" Message digest:\r\n"); TRACE_DEBUG_ARRAY(" ", digest, hash->digestSize); //Initialize multiple-precision integers mpiInit(&m); mpiInit(&s); //Get the length in octets of the modulus n k = mpiGetByteLength(&key->n); //Point to the buffer where the encoded message EM will be generated em = signature; //Apply the EMSA-PKCS1-v1.5 encoding operation error = emsaPkcs1v15Encode(hash, digest, em, k); //Any error to report? if(error) return error; //Debug message TRACE_DEBUG(" Encoded message\r\n"); TRACE_DEBUG_ARRAY(" ", em, k); //Start of exception handling block do { //Convert the encoded message EM to an integer message representative m error = mpiReadRaw(&m, em, k); //Conversion failed? if(error) break; //Apply the RSASP1 signature primitive error = rsasp1(key, &m, &s); //Any error to report? if(error) break; //Convert the signature representative s to a signature of length k octets error = mpiWriteRaw(&s, signature, k); //Conversion failed? if(error) break; //Length of the resulting signature *signatureLength = k; //Debug message TRACE_DEBUG(" Signature:\r\n"); TRACE_DEBUG_ARRAY(" ", signature, *signatureLength); //End of exception handling block } while(0); //Free previously allocated memory mpiFree(&m); mpiFree(&s); //Return status code return error; }
error_t rsaesPkcs1v15Decrypt(const RsaPrivateKey *key, const uint8_t *ciphertext, size_t ciphertextLength, uint8_t *message, size_t messageSize, size_t *messageLength) { error_t error; uint_t i; uint_t k; uint8_t *em; Mpi c; Mpi m; //Check parameters if(key == NULL || ciphertext == NULL) return ERROR_INVALID_PARAMETER; if(message == NULL || messageLength == NULL) return ERROR_INVALID_PARAMETER; //Debug message TRACE_DEBUG("RSA PKCS #1 v1.5 decryption...\r\n"); TRACE_DEBUG(" Modulus:\r\n"); TRACE_DEBUG_MPI(" ", &key->n); TRACE_DEBUG(" Public exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->e); TRACE_DEBUG(" Private exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->d); TRACE_DEBUG(" Prime 1:\r\n"); TRACE_DEBUG_MPI(" ", &key->p); TRACE_DEBUG(" Prime 2:\r\n"); TRACE_DEBUG_MPI(" ", &key->q); TRACE_DEBUG(" Prime exponent 1:\r\n"); TRACE_DEBUG_MPI(" ", &key->dp); TRACE_DEBUG(" Prime exponent 2:\r\n"); TRACE_DEBUG_MPI(" ", &key->dq); TRACE_DEBUG(" Coefficient:\r\n"); TRACE_DEBUG_MPI(" ", &key->qinv); TRACE_DEBUG(" Ciphertext:\r\n"); TRACE_DEBUG_ARRAY(" ", ciphertext, ciphertextLength); //Initialize multiple-precision integers mpiInit(&c); mpiInit(&m); //Get the length in octets of the modulus n k = mpiGetByteLength(&key->n); //Check the length of the ciphertext if(ciphertextLength != k || ciphertextLength < 11) return ERROR_INVALID_LENGTH; //Allocate a buffer to store the encoded message EM em = osAllocMem(k); //Failed to allocate memory? if(!em) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Convert the ciphertext to an integer ciphertext representative c error = mpiReadRaw(&c, ciphertext, ciphertextLength); //Conversion failed? if(error) break; //Apply the RSADP decryption primitive error = rsadp(key, &c, &m); //Any error to report? if(error) break; //Convert the message representative m to an encoded message EM of length k octets error = mpiWriteRaw(&m, em, k); //Conversion failed? if(error) break; //Debug message TRACE_DEBUG(" Encoded message\r\n"); TRACE_DEBUG_ARRAY(" ", em, k); //The first octet of EM must have a value of 0x00 //and the block type BT shall be 0x02 if(em[0] != 0x00 || em[1] != 0x02) { //Report an error error = ERROR_UNEXPECTED_VALUE; break; } //An octet with hexadecimal value 0x00 is used to separate PS from M for(i = 2; i < k && em[i] != 0x00; i++); //Check whether the padding string is valid if(i < 10 || i >= k) { //Report an error error = ERROR_INVALID_PADDING; break; } //Ensure that the output buffer is large enough if(messageSize < (k - i - 1)) { //Report an error error = ERROR_INVALID_LENGTH; break; } //Recover the length of the message *messageLength = k - i - 1; //Copy the message contents memcpy(message, em + i + 1, *messageLength); //Debug message TRACE_DEBUG(" Message:\r\n"); TRACE_DEBUG_ARRAY(" ", message, *messageLength); //End of exception handling block } while(0); //Release multiple precision integers mpiFree(&c); mpiFree(&m); //Free previously allocated memory osFreeMem(em); //Return status code return error; }
error_t rsaesPkcs1v15Encrypt(const PrngAlgo *prngAlgo, void *prngContext, const RsaPublicKey *key, const uint8_t *message, size_t messageLength, uint8_t *ciphertext, size_t *ciphertextLength) { error_t error; uint_t i; uint_t j; uint_t k; uint_t n; uint8_t *p; Mpi m; Mpi c; //Check parameters if(key == NULL || message == NULL) return ERROR_INVALID_PARAMETER; if(ciphertext == NULL || ciphertextLength == NULL) return ERROR_INVALID_PARAMETER; //Debug message TRACE_DEBUG("RSA PKCS #1 v1.5 encryption...\r\n"); TRACE_DEBUG(" Modulus:\r\n"); TRACE_DEBUG_MPI(" ", &key->n); TRACE_DEBUG(" Public exponent:\r\n"); TRACE_DEBUG_MPI(" ", &key->e); TRACE_DEBUG(" Message:\r\n"); TRACE_DEBUG_ARRAY(" ", message, messageLength); //Initialize multiple-precision integers mpiInit(&m); mpiInit(&c); //Get the length in octets of the modulus n k = mpiGetByteLength(&key->n); //Check the length of the message if((messageLength + 11) > k) return ERROR_INVALID_LENGTH; //Point to the buffer where the encoded message EM will be formatted p = ciphertext; //The leading 0x00 octet ensures that the encoded message, //converted to an integer, is less than the modulus *(p++) = 0x00; //For a public-key operation, the block type BT shall be 0x02 *(p++) = 0x02; //Length of the padding string PS n = k - messageLength - 3; //Generate the padding string (pseudo-randomly generated non-zero octets) while(n > 0) { //Generate random data error = prngAlgo->read(prngContext, p, n); //Any error to report? if(error) return error; //Parse the resulting octet string for(i = 0, j = 0; j < n; j++) { //Strip any byte with a value of zero if(p[j] != 0) p[i++] = p[j]; } //Advance data pointer p += i; n -= i; } //Append a 0x00 octet to the padding string *(p++) = 0x00; //Copy the message to be encrypted memcpy(p, message, messageLength); //Rewind to the beginning of the encoded message p = ciphertext; //Debug message TRACE_DEBUG(" Encoded message\r\n"); TRACE_DEBUG_ARRAY(" ", p, k); //Start of exception handling block do { //Convert the encoded message EM to an integer message representative m error = mpiReadRaw(&m, p, k); //Conversion failed? if(error) break; //Apply the RSAEP encryption primitive error = rsaep(key, &m, &c); //Any error to report? if(error) break; //Convert the ciphertext representative c to a ciphertext of length k octets error = mpiWriteRaw(&c, ciphertext, k); //Conversion failed? if(error) break; //Length of the resulting ciphertext *ciphertextLength = k; //Debug message TRACE_DEBUG(" Ciphertext:\r\n"); TRACE_DEBUG_ARRAY(" ", ciphertext, *ciphertextLength); //End of exception handling block } while(0); //Free previously allocated memory mpiFree(&m); mpiFree(&c); //Return status code return error; }