void cdk_keygen_set_passphrase( cdk_keygen_ctx_t hd, const char * pass ) { if( !hd ) return; if( pass ) { size_t n = strlen( pass ); _cdk_sec_free( hd->pass, hd->pass_len ); hd->pass = cdk_salloc( n + 1, 1 ); if( hd->pass ) { memcpy( hd->pass, pass, n ); hd->pass[n] = '\0'; hd->pass_len = n; hd->protect = 1; } } }
static int gcry_mpi_to_native( cdk_keygen_ctx_t hd, size_t nkey, int type, cdk_pkt_pubkey_t pk, cdk_pkt_seckey_t sk ) { gcry_mpi_t * resarr; cdk_mpi_t a = NULL; size_t nbytes; int i = 0, j = 0, nbits; int rc = 0; if( !hd ) return CDK_Inv_Value; if( !pk && !sk ) return CDK_Inv_Value; if( type < 0 || type > 1 ) return CDK_Inv_Value; resarr = hd->key[type].resarr; if( sk ) i += cdk_pk_get_npkey( sk->pubkey_algo ); while( j != nkey ) { nbits = gcry_mpi_get_nbits( resarr[i] ); if( pk ) a = cdk_calloc( 1, sizeof * a + (nbits + 7) / 8 + 2 + 1 ); else if( sk ) a = cdk_salloc( sizeof * a + (nbits + 7) / 8 + 2 + 1, 1 ); a->bits = nbits; a->bytes = ( nbits + 7 ) / 8; nbytes = a->bytes; a->data[0] = nbits >> 8; a->data[1] = nbits; rc = gcry_mpi_print( GCRYMPI_FMT_USG, a->data+2, nbytes, &nbytes, resarr[i] ); if( rc ) break; if( pk ) pk->mpi[j++] = a; else if( sk ) sk->mpi[j++] = a; i++; } return rc; }
/** * 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; }