error_t ecExport(const EcDomainParameters *params, const EcPoint *a, uint8_t *data, size_t *length) { error_t error; size_t k; //Get the length in octets of the prime k = mpiGetByteLength(¶ms->p); //Point compression is not used data[0] = 0x04; //Convert the x-coordinate to an octet string error = mpiWriteRaw(&a->x, data + 1, k); //Conversion failed? if(error) return error; //Convert the y-coordinate to an octet string error = mpiWriteRaw(&a->y, data + k + 1, k); //Conversion failed? if(error) return error; //Return the total number of bytes that have been written *length = k * 2 + 1; //Successful processing return NO_ERROR; }
error_t ecImport(const EcDomainParameters *params, EcPoint *r, const uint8_t *data, size_t length) { error_t error; size_t k; //Get the length in octets of the prime k = mpiGetByteLength(¶ms->p); //Check the length of the octet string if(length != (k * 2 + 1)) return ERROR_DECODING_FAILED; //Compressed point representation is not supported if(data[0] != 0x04) return ERROR_ILLEGAL_PARAMETER; //Convert the x-coordinate to a multiple precision integer error = mpiReadRaw(&r->x, data + 1, k); //Any error to report? if(error) return error; //Convert the y-coordinate to a multiple precision integer error = mpiReadRaw(&r->y, data + k + 1, k); //Any error to report? if(error) return error; //Successful processing return NO_ERROR; }
error_t dhComputeSharedSecret(DhContext *context, uint8_t *output, size_t outputSize, size_t *outputLength) { error_t error; size_t k; Mpi z; //Debug message TRACE_DEBUG("Computing Diffie-Hellman shared secret...\r\n"); //Get the length in octets of the prime modulus k = mpiGetByteLength(&context->params.p); //Make sure that the output buffer is large enough if(outputSize < k) return ERROR_INVALID_LENGTH; //The multiple precision integer must be initialized before it can be used mpiInit(&z); //Start of exception handling block do { //Calculate the shared secret key (k = yb ^ xa mod p) error = mpiExpMod(&z, &context->yb, &context->xa, &context->params.p); //Any error to report? if(error) return error; //Convert the resulting integer to an octet string error = mpiWriteRaw(&z, output, k); //Conversion failed? if(error) return error; //Length of the resulting shared secret *outputLength = k; //Debug message TRACE_DEBUG(" Shared secret (%" PRIuSIZE " bytes):\r\n", *outputLength); TRACE_DEBUG_ARRAY(" ", output, *outputLength); //End of exception handling block } while(0); //Release previously allocated resources mpiFree(&z); //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; }