cdk_error_t _cdk_copy_seckey (cdk_pkt_seckey_t* dst, cdk_pkt_seckey_t src) { cdk_pkt_seckey_t k; int i; if (!dst || !src) return CDK_Inv_Value; *dst = NULL; k = cdk_calloc (1, sizeof *k); if (!k) return CDK_Out_Of_Core; memcpy (k, src, sizeof *k); _cdk_copy_pubkey (&k->pk, src->pk); if (src->encdata) { k->encdata = cdk_calloc (1, src->enclen + 1); if (!k->encdata) return CDK_Out_Of_Core; memcpy (k->encdata, src->encdata, src->enclen); } _cdk_s2k_copy (&k->protect.s2k, src->protect.s2k); for (i = 0; i < cdk_pk_get_nskey (src->pubkey_algo); i++) { k->mpi[i] = gcry_mpi_copy (src->mpi[i]); gcry_mpi_set_flag (k->mpi[i], GCRYMPI_FLAG_SECURE); } *dst = k; return 0; }
int deserialize_mpi(gcry_mpi_t *x, enum disp_format df, const char *buf, int inlen) { switch(df) { case DF_BIN: gcry_mpi_scan(x, GCRYMPI_FMT_USG, buf, inlen, NULL); gcry_mpi_set_flag(*x, GCRYMPI_FLAG_SECURE); break; case DF_COMPACT: case DF_BASE36: do { const char *digits = get_digits(df); unsigned int digit_count = get_digit_count(df); char *d; int i; *x = gcry_mpi_snew(0); for(i = 0; i < inlen; i++) { if (! (d = memchr(digits, buf[i], digit_count))) { gcry_mpi_release(*x); return 0; } gcry_mpi_mul_ui(*x, *x, digit_count); gcry_mpi_add_ui(*x, *x, d - digits); } } while (0); break; default: assert(0); } return 1; }
gcry_mpi_t buf_to_exponent(const char *buf, int buflen, const struct curve_params *cp) { gcry_mpi_t a, b; gcry_mpi_scan(&a, GCRYMPI_FMT_USG, buf, buflen, NULL); gcry_mpi_set_flag(a, GCRYMPI_FLAG_SECURE); b = gcry_mpi_new(0); gcry_mpi_sub_ui(b, cp->dp.order, 1); gcry_mpi_mod(a, a, b); gcry_mpi_add_ui(a, a, 1); gcry_mpi_release(b); return a; }
/* Algorithms 4.29 and 4.30 in the "Guide to Elliptic Curve Cryptography" */ gcry_mpi_t ECDSA_sign(const char *msg, const gcry_mpi_t d, const struct curve_params *cp) { struct affine_point p1; gcry_mpi_t e, k, r, s; #if ECDSA_DETERMINISTIC struct aes256cprng *cprng; cprng = ecdsa_cprng_init(msg, d, cp); #endif r = gcry_mpi_snew(0); s = gcry_mpi_snew(0); Step1: #if ECDSA_DETERMINISTIC k = ecdsa_cprng_get_exponent(cprng, cp); #else k = get_random_exponent(cp); #endif p1 = pointmul(&cp->dp.base, k, &cp->dp); gcry_mpi_mod(r, p1.x, cp->dp.order); point_release(&p1); if (! gcry_mpi_cmp_ui(r, 0)) { gcry_mpi_release(k); goto Step1; } gcry_mpi_scan(&e, GCRYMPI_FMT_USG, msg, 64, NULL); gcry_mpi_set_flag(e, GCRYMPI_FLAG_SECURE); gcry_mpi_mod(e, e, cp->dp.order); gcry_mpi_mulm(s, d, r, cp->dp.order); gcry_mpi_addm(s, s, e, cp->dp.order); gcry_mpi_invm(e, k, cp->dp.order); gcry_mpi_mulm(s, s, e, cp->dp.order); gcry_mpi_release(e); gcry_mpi_release(k); if (! gcry_mpi_cmp_ui(s, 0)) goto Step1; gcry_mpi_mul(s, s, cp->dp.order); gcry_mpi_add(s, s, r); gcry_mpi_release(r); #if ECDSA_DETERMINISTIC ecdsa_cprng_done(cprng); #endif return s; }
static int test_const_and_immutable (void) { gcry_mpi_t one, second_one; one = gcry_mpi_set_ui (NULL, 1); if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE) || gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("immutable or const flag initially set\n"); second_one = gcry_mpi_copy (one); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag set after copy\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag set after copy\n"); gcry_mpi_release (second_one); gcry_mpi_set_flag (one, GCRYMPI_FLAG_IMMUTABLE); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)) die ("failed to set immutable flag\n"); if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("const flag unexpectly set\n"); second_one = gcry_mpi_copy (one); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag not cleared after copy\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag unexpectly set after copy\n"); gcry_mpi_release (second_one); gcry_mpi_clear_flag (one, GCRYMPI_FLAG_IMMUTABLE); if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)) die ("failed to clear immutable flag\n"); if (gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("const flag unexpectly set\n"); gcry_mpi_set_flag (one, GCRYMPI_FLAG_CONST); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("failed to set const flag\n"); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)) die ("failed to set immutable flag with const flag\n"); second_one = gcry_mpi_copy (one); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag not cleared after copy\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag not cleared after copy\n"); gcry_mpi_release (second_one); gcry_mpi_clear_flag (one, GCRYMPI_FLAG_IMMUTABLE); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_IMMUTABLE)) die ("clearing immutable flag not ignored for a constant MPI\n"); if (!gcry_mpi_get_flag (one, GCRYMPI_FLAG_CONST)) die ("const flag unexpectly cleared\n"); second_one = gcry_mpi_set (NULL, GCRYMPI_CONST_ONE); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag not cleared by mpi_set (NULL,x)\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag not cleared by mpi_set (NULL,x)\n"); gcry_mpi_release (second_one); second_one = gcry_mpi_set_ui (NULL, 42); gcry_mpi_set (second_one, GCRYMPI_CONST_ONE); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_IMMUTABLE)) die ("immutable flag not cleared after mpi_set (a,x)\n"); if (gcry_mpi_get_flag (second_one, GCRYMPI_FLAG_CONST)) die ("const flag not cleared mpi_set (a,x)\n"); gcry_mpi_release (second_one); /* Due to the the constant flag the release below should be a NOP and will leak memory. */ gcry_mpi_release (one); return 1; }
/** * cdk_sk_unprotect: * @sk: the secret key * @pw: the passphrase * * Unprotect the given secret key with the passphrase. **/ cdk_error_t cdk_sk_unprotect (cdk_pkt_seckey_t sk, const char *pw) { gcry_cipher_hd_t hd; cdk_dek_t dek = NULL; byte *data = NULL; u16 chksum = 0; size_t ndata, nbits, nbytes; int i, dlen, pos = 0, nskey; cdk_error_t rc; gcry_error_t err; if (!sk) return CDK_Inv_Value; nskey = cdk_pk_get_nskey (sk->pubkey_algo); if (!sk->is_protected) { chksum = 0; for (i = 0; i < nskey; i++) chksum += checksum_mpi (sk->mpi[i]); if (chksum != sk->csum) return CDK_Chksum_Error; } rc = cdk_dek_from_passphrase (&dek, sk->protect.algo, sk->protect.s2k, 0, pw); if (rc) return rc; err = gcry_cipher_open (&hd, sk->protect.algo, GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_ENABLE_SYNC); if (!err) err = gcry_cipher_setiv (hd, sk->protect.iv, sk->protect.ivlen); if (!err) err = gcry_cipher_setkey (hd, dek->key, dek->keylen); if (err) { cdk_free (dek); return map_gcry_error (err); } cdk_dek_free (dek); chksum = 0; if (sk->version == 4) { ndata = sk->enclen; data = cdk_salloc (ndata, 1); if (!data) return CDK_Out_Of_Core; gcry_cipher_decrypt (hd, data, ndata, sk->encdata, ndata); if (sk->protect.sha1chk) { /* This is the new SHA1 checksum method to detect tampering with the key as used by the Klima/Rosa attack */ sk->csum = 0; chksum = 1; dlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1); if (ndata < dlen) { cdk_free (data); return CDK_Inv_Packet; } else { byte mdcheck[20]; gcry_md_hash_buffer (GCRY_MD_SHA1, mdcheck, data, ndata-dlen); if (!memcmp (mdcheck, data + ndata - dlen, dlen)) chksum = 0; /* Digest does match */ } } else { for (i = 0; i < ndata - 2; i++) chksum += data[i]; sk->csum = data[ndata - 2] << 8 | data[ndata - 1]; } if (sk->csum == chksum) { for (i = 0; i < nskey; i++) { nbits = data[pos] << 8 | data[pos + 1]; if (gcry_mpi_scan (&sk->mpi[i], GCRYMPI_FMT_PGP, data, (nbits+7)/8+2, &nbytes)) { wipemem (data, sk->enclen); cdk_free (data); return CDK_Wrong_Format; } gcry_mpi_set_flag (sk->mpi[i], GCRYMPI_FLAG_SECURE); pos += (nbits+7)/8+2; } } wipemem (data, sk->enclen); cdk_free (data); } else { byte buf[MAX_MPI_BYTES+2]; chksum = 0; for (i = 0; i < nskey; i++) { gcry_cipher_sync (hd); gcry_mpi_print (GCRYMPI_FMT_PGP, buf, DIM (buf), &nbytes, sk->mpi[i]); gcry_cipher_decrypt (hd, buf+2, nbytes-2, NULL, 0); gcry_mpi_release (sk->mpi[i]); if (gcry_mpi_scan (&sk->mpi[i], GCRYMPI_FMT_PGP, buf, nbytes, &nbytes)) return CDK_Wrong_Format; chksum += checksum_mpi (sk->mpi[i]); } } gcry_cipher_close (hd); if (chksum != sk->csum) return CDK_Chksum_Error; sk->is_protected = 0; return 0; }