int rsa_wire2prikey(uint8_t *in, size_t inlen, RSA_KEY *key) { memset(key, 0, sizeof(RSA_KEY)); key->bits = decbe64(in); size_t p_len = ((key->bits / 2) + 7) / 8; if(inlen < 8 + 2 * p_len + (key->bits + 7) / 8 + 8) { goto error; } if(os2ip(&key->p, &in[8], p_len) != 0) { goto error; } if(os2ip(&key->q, &in[8 + p_len], p_len) != 0) { goto error; } if(os2ip(&key->d, &in[8 + 2 * p_len], (key->bits + 7) / 8) != 0) { goto error; } key->e = decbe64(&in[p_len * 2 + (key->bits + 7) / 8 + 8]); if(bno_mul(&key->n, &key->p, &key->q) != 0) { goto error; } return 0; error: memset(key, 0, sizeof(RSA_KEY)); return 1; }
int rsa_wire_prikey2pubkey(uint8_t *in, size_t inlen, uint8_t *out, size_t outlen) { uint64_t bits = decbe64(in); size_t p_len = ((bits / 2) + 7) / 8; int ret = 0; if(inlen < rsa_prikey_bufsize(bits) || outlen < rsa_pubkey_bufsize(bits)) { return -1; } bignum n = BN_ZERO, p = BN_ZERO, q = BN_ZERO; if(os2ip(&p, &in[8], p_len) != 0) { goto error; } if(os2ip(&q, &in[8+p_len], p_len) != 0) { goto error; } if(bno_mul(&n, &p, &q) != 0) { goto error; } memcpy(out, in, 8); i2osp(&out[8], (bits + 7) / 8, &n); memcpy(&out[rsa_pubkey_bufsize(bits) - 8], &in[rsa_prikey_bufsize(bits) - 8], 8); goto cleanup; error: ret = 1; cleanup: ret |= bnu_free(&n); ret |= bnu_free(&p); ret |= bnu_free(&q); return ret; }
int rsa_wire2pubkey(uint8_t *in, size_t inlen, RSA_PUBLIC_KEY *key) { key->n = BN_ZERO; key->bits = decbe64(in); if(inlen < (key->bits + 7) / 8 + 8) { return 1; } if(os2ip(&key->n, &in[8], (key->bits + 7) / 8) != 0) { goto error; } key->e = decbe64(&in[8 + (key->bits + 7) / 8]); return 0; error: memset(key, 0, sizeof(RSA_PUBLIC_KEY)); return 1; }
int mpbsetbin(mpbarrett* b, const byte* osdata, size_t ossize) { int rc = -1; size_t size; /* skip zero bytes */ while (!(*osdata) && ossize) { osdata++; ossize--; } size = MP_BYTES_TO_WORDS(ossize + MP_WBYTES - 1); if (b->modl) { if (b->size != size) b->modl = (mpw*) realloc(b->modl, (2*size+1) * sizeof(mpw)); } else b->modl = (mpw*) malloc((2*size+1) * sizeof(mpw)); if (b->modl) { register mpw* temp = (mpw*) malloc((6*size+4) * sizeof(mpw)); b->size = size; b->mu = b->modl+size; rc = os2ip(b->modl, size, osdata, ossize); mpbmu_w(b, temp); free(temp); } return rc; }
int rsa_pss_verify(RSA_PUBLIC_KEY *key, uint8_t *sig, size_t siglen, uint8_t *message, size_t mlen, int *valid) { if(key == NULL || sig == NULL || message == NULL || valid == NULL) { return -1; } const size_t emlen = (key->bits - 2) / 8 + 1; const size_t hlen = 32; const size_t slen = hlen; SHA256_CTX ctx; uint8_t hash[hlen]; uint8_t zeroes[8]; uint8_t *em = NULL; uint8_t *mask = NULL; bignum em_bn = BN_ZERO; bignum s_bn = BN_ZERO; int ret; *valid = 0; if((em = malloc(emlen)) == NULL) { return MALLOC_FAIL; } if((mask = malloc(emlen - hlen - 1)) == NULL) { ret = MALLOC_FAIL; goto err; } if((ret = os2ip(&s_bn, sig, siglen)) != 0) { /* cleanup is non-necessary here, but no harm */ goto err; } if((ret = rsa_encrypt(key, &s_bn, &em_bn)) != 0) { goto err; } if((ret = i2osp(em, emlen, &em_bn)) != 0) { goto err; } mgf1_sha256(&em[emlen - hlen - 1], hlen, emlen - hlen - 1, mask); xor_bytes(em, mask, emlen - hlen - 1, em); sha256_init(&ctx); sha256_update(&ctx, message, mlen); sha256_final(&ctx, hash); memset(zeroes, 0x00, 8); sha256_init(&ctx); sha256_update(&ctx, zeroes, 8); sha256_update(&ctx, hash, hlen); sha256_update(&ctx, &em[emlen - hlen - slen - 1], slen); sha256_final(&ctx, hash); xor_bytes(&em[emlen - hlen - 1], hash, hlen, &em[emlen - hlen - 1]); em[emlen - hlen - slen - 2] ^= 0x01; em[emlen - 1] ^= 0xbc; em[0] &= ((uint8_t) 0xff) >> (emlen * 8 - (key->bits - 2)); memset(&em[emlen - hlen - slen - 1], 0x00, slen); size_t i; uint8_t val = 0; for(i = 0; i < emlen; i++) { val |= (em[i]); } if(val) { *valid = 0; } else { *valid = 1; } ret = 0; err: memsets(&ctx, 0x00, sizeof(SHA256_CTX)); memsets(hash, 0x00, hlen); if(em) zfree(em, emlen); if(mask) zfree(mask, emlen - hlen - 1); bnu_free(&em_bn); bnu_free(&s_bn); return ret; }
int rsa_pss_sign(RSA_KEY *key, uint8_t *message, size_t mlen, uint8_t *out, size_t outlen) { if(key == NULL || message == NULL || out == NULL) { return -1; } const size_t k = (key->bits - 1) / 8 + 1; const size_t emlen = (key->bits - 2) / 8 + 1; const size_t hlen = 32; const size_t slen = hlen; SHA256_CTX ctx; uint8_t mhash[hlen]; uint8_t salt[slen]; uint8_t zeroes[8]; uint8_t *em = NULL; bignum em_bn = BN_ZERO; bignum s_bn = BN_ZERO; int ret; if(outlen < k) { /* avoid buffer overflows */ return TOO_SHORT; } if(emlen < hlen + slen + 2) { /* key too small to sign */ return CRYPTOGRAPHY_ERROR; } /* allocate space for em */ if((em = malloc(emlen)) == NULL) { return MALLOC_FAIL; } /* generate salt, as we can still exit without cleanup if this fails */ if(cs_rand(salt, slen) != 0) { return CRYPTOGRAPHY_ERROR; } sha256_init(&ctx); sha256_update(&ctx, message, mlen); sha256_final(&ctx, mhash); /* calculate H = sha256(0x00 00 00 00 00 00 00 00 || mhash || salt) */ memset(zeroes, 0x00, 8); sha256_init(&ctx); sha256_update(&ctx, zeroes, 8); sha256_update(&ctx, mhash, hlen); sha256_update(&ctx, salt, slen); sha256_final(&ctx, &em[emlen - hlen - 1]); mgf1_sha256(&em[emlen - hlen - 1], hlen, emlen - hlen - 1, em); /* xor in 0x01 and salt */ em[emlen - slen - hlen - 2] ^= 0x01; xor_bytes(&em[emlen - slen - hlen - 1], salt, slen, &em[emlen - slen - hlen - 1]); em[emlen - 1] = 0xbc; em[0] &= ((uint8_t) 0xff) >> (8 * emlen - (key->bits - 2)); if((ret = os2ip(&em_bn, em, emlen)) != 0) { goto err; } if((ret = rsa_decrypt(key, &em_bn, &s_bn)) != 0) { goto err; } if((ret = i2osp(out, outlen, &s_bn)) != 0) { goto err; } ret = 0; err: memsets(mhash, 0, hlen); memsets(salt, 0, slen); memsets(&ctx, 0, sizeof(SHA256_CTX)); bnu_free(&s_bn); bnu_free(&em_bn); if(em) zfree(em, emlen); return ret; }
int rsa_oaep_decrypt(RSA_KEY *key, uint8_t *ctext, size_t clen, uint8_t *out, size_t outlen) { if(key == NULL || ctext == NULL || out == NULL) { return -1; } const size_t k = (key->bits - 1) / 8 + 1; const size_t hlen = 32; bignum c_bn = BN_ZERO; bignum m_bn = BN_ZERO; uint8_t *em = NULL; uint8_t *db = NULL; uint8_t *mask = NULL; uint8_t seed[hlen]; size_t message_start; int ret; /* nothing critical yet */ if((ret = os2ip(&c_bn, ctext, clen)) != 0) { return ret; } /* now sensitive information is contained in our buffers, so we have * to clean up */ if((ret = rsa_decrypt(key, &c_bn, &m_bn)) != 0) { goto err; } if((em = malloc(k)) == NULL) { ret = MALLOC_FAIL; goto err; } if((ret = i2osp(em, k, &m_bn)) != 0) { goto err; } db = em + hlen + 1; if((mask = malloc(k - hlen - 1)) == NULL) { ret = MALLOC_FAIL; goto err; } /* calculate seed mask = MGF1(maskedDB, k - hlen - 1) */ mgf1_sha256(db, k - hlen - 1, hlen, mask); /* calculate seed */ xor_bytes(em + 1, mask, hlen, seed); /* calculate dbMask */ mgf1_sha256(seed, hlen, k - hlen - 1, mask); /* unmask db */ xor_bytes(db, mask, k - hlen - 1, db); /* find the start of the message */ for(message_start = hlen; message_start < k - hlen - 1 && db[message_start] == 0x00; message_start++) {} uint8_t valid = 0; valid |= memcmp_ct(db, lhash, 32); valid |= em[0]; valid |= !(message_start != k - hlen - 1 && db[message_start] == 1); /* if valid is non-zero this is not a valid message */ if(valid != 0) { ret = CRYPTOGRAPHY_ERROR; goto err; } message_start++; /* prevent buffer overflows */ if(outlen < k - hlen - 1 - message_start) { ret = TOO_SHORT; goto err; } memcpy(out, &db[message_start], k - hlen - 1 - message_start); ret = 0; err: ret = ret == 0 ? bnu_free(&c_bn) : ret; ret = ret == 0 ? bnu_free(&m_bn) : ret; if(em) zfree(em, k); if(mask) zfree(mask, k - hlen - 1); memsets(seed, 0x00, hlen); return ret; }
int rsa_oaep_encrypt(RSA_PUBLIC_KEY *key, uint8_t *message, size_t mlen, uint8_t *out, size_t outlen) { if(key == NULL || message == NULL || out == NULL) { return -1; } const size_t k = (key->bits - 1) / 8 + 1; const size_t hlen = 32; uint8_t seed[hlen]; uint8_t *mask; uint8_t *em; uint8_t *db; bignum m_bn; bignum c_bn; int ret; /* message is too long to encrypt */ if(k - 2 * hlen - 2 < mlen) { return TOO_LONG; } /* output buffer is too small */ if(outlen < k) { return TOO_SHORT; } /* do stuff involving the masks first, as in case of error it does not * need to be kept secure */ if(cs_rand(seed, hlen) != 0) { return CRYPTOGRAPHY_ERROR; } if((mask = malloc(k - hlen - 1)) == NULL) { return MALLOC_FAIL; } /* calculate dbMask = MGF(seed, k - hLen - 1) */ mgf1_sha256(seed, hlen, k - hlen - 1, mask); /* now initialize the string to be encrypted */ if((em = malloc(k)) == NULL) { return MALLOC_FAIL; } /* from now on we have to clean up memory after any failures */ /* em[hlen:] is all DB = lhash || PS || 0x01 || M */ db = em + hlen + 1; memcpy(db, lhash, hlen); /* PS is a padding string of zeroes */ memset(db + hlen, 0x00, k - 2 * hlen - mlen - 2); /* there is then one byte of value 0x01 */ db[k - 2 - hlen - mlen] = 0x01; /* then message */ memcpy(&db[k - hlen - 1 - mlen], message, mlen); /* now apply the mask to it */ xor_bytes(db, mask, k - hlen - 1, db); /* now we can repurpose mask to encode the seed mask */ mgf1_sha256(db, k - hlen - 1, hlen, mask); /* xor it into em */ xor_bytes(seed, mask, hlen, em + 1); em[0] = 0x00; m_bn = BN_ZERO; c_bn = BN_ZERO; /* now convert to a big integer */ if((ret = os2ip(&m_bn, em, k)) != 0) { goto err; } /* encrypt */ if((ret = rsa_encrypt(key, &m_bn, &c_bn)) != 0) { goto err; } /* convert back */ if((ret = i2osp(out, outlen, &c_bn)) != 0) { goto err; } /* encryption is officially done, clean up */ ret = 0; err: /* free mask and em, zero seed */ zfree(mask, k - hlen - 1); zfree(em, k - 1); memsets(seed, 0x00, hlen); /* free the bignums */ /* an error here is still an error as it is a possible leak of * sensitive data */ ret = ret == 0 ? bnu_free(&m_bn) : ret; ret = ret == 0 ? bnu_free(&c_bn) : ret; return ret; }