|
|
|
@ -301,154 +301,156 @@ write_seckey_body(const pgp_seckey_t *key,
|
|
|
|
|
if (!write_pubkey_body(&key->pubkey, output)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (key->s2k_usage != PGP_S2KU_ENCRYPTED_AND_HASHED) {
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: s2k usage\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write_scalar(output, (unsigned)key->s2k_usage, 1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (key->s2k_usage != PGP_S2KU_NONE) {
|
|
|
|
|
if (key->s2k_usage != PGP_S2KU_ENCRYPTED_AND_HASHED) {
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: s2k usage\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write_scalar(output, (unsigned)key->s2k_usage, 1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key->alg != PGP_SA_CAST5) {
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: algorithm\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write_scalar(output, (unsigned)key->alg, 1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (key->alg != PGP_SA_CAST5) {
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: algorithm\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write_scalar(output, (unsigned)key->alg, 1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key->s2k_specifier != PGP_S2KS_SIMPLE &&
|
|
|
|
|
key->s2k_specifier != PGP_S2KS_SALTED) {
|
|
|
|
|
/* = 1 \todo could also be iterated-and-salted */
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: s2k spec\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write_scalar(output, (unsigned)key->s2k_specifier, 1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write_scalar(output, (unsigned)key->hash_alg, 1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (key->s2k_specifier != PGP_S2KS_SIMPLE &&
|
|
|
|
|
key->s2k_specifier != PGP_S2KS_SALTED) {
|
|
|
|
|
/* = 1 \todo could also be iterated-and-salted */
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: s2k spec\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write_scalar(output, (unsigned)key->s2k_specifier, 1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write_scalar(output, (unsigned)key->hash_alg, 1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (key->s2k_specifier) {
|
|
|
|
|
case PGP_S2KS_SIMPLE:
|
|
|
|
|
/* nothing more to do */
|
|
|
|
|
break;
|
|
|
|
|
switch (key->s2k_specifier) {
|
|
|
|
|
case PGP_S2KS_SIMPLE:
|
|
|
|
|
/* nothing more to do */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PGP_S2KS_SALTED:
|
|
|
|
|
/* 8-octet salt value */
|
|
|
|
|
pgp_random(__UNCONST(&key->salt[0]), PGP_SALT_SIZE);
|
|
|
|
|
if (!pgp_write(output, key->salt, PGP_SALT_SIZE)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PGP_S2KS_SALTED:
|
|
|
|
|
/* 8-octet salt value */
|
|
|
|
|
pgp_random(__UNCONST(&key->salt[0]), PGP_SALT_SIZE);
|
|
|
|
|
if (!pgp_write(output, key->salt, PGP_SALT_SIZE)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* \todo case PGP_S2KS_ITERATED_AND_SALTED: // 8-octet salt
|
|
|
|
|
* value // 1-octet count break;
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
* \todo case PGP_S2KS_ITERATED_AND_SALTED: // 8-octet salt
|
|
|
|
|
* value // 1-octet count break;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
(void) fprintf(stderr,
|
|
|
|
|
"invalid/unsupported s2k specifier %d\n",
|
|
|
|
|
key->s2k_specifier);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
(void) fprintf(stderr,
|
|
|
|
|
"invalid/unsupported s2k specifier %d\n",
|
|
|
|
|
key->s2k_specifier);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pgp_write(output, &key->iv[0], pgp_block_size(key->alg))) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!pgp_write(output, &key->iv[0], pgp_block_size(key->alg))) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* create the session key for encrypting the algorithm-specific
|
|
|
|
|
* fields
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
* create the session key for encrypting the algorithm-specific
|
|
|
|
|
* fields
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
switch (key->s2k_specifier) {
|
|
|
|
|
case PGP_S2KS_SIMPLE:
|
|
|
|
|
case PGP_S2KS_SALTED:
|
|
|
|
|
/* RFC4880: section 3.7.1.1 and 3.7.1.2 */
|
|
|
|
|
|
|
|
|
|
for (done = 0, i = 0; done < CAST_KEY_LENGTH; i++) {
|
|
|
|
|
unsigned hashsize;
|
|
|
|
|
unsigned j;
|
|
|
|
|
unsigned needed;
|
|
|
|
|
unsigned size;
|
|
|
|
|
uint8_t zero = 0;
|
|
|
|
|
|
|
|
|
|
/* Hard-coded SHA1 for session key */
|
|
|
|
|
pgp_hash_any(&hash, PGP_HASH_SHA1);
|
|
|
|
|
hashsize = pgp_hash_size(key->hash_alg);
|
|
|
|
|
needed = CAST_KEY_LENGTH - done;
|
|
|
|
|
size = MIN(needed, hashsize);
|
|
|
|
|
if ((hashed = calloc(1, hashsize)) == NULL) {
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: bad alloc\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!hash.init(&hash)) {
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: bad alloc\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
switch (key->s2k_specifier) {
|
|
|
|
|
case PGP_S2KS_SIMPLE:
|
|
|
|
|
case PGP_S2KS_SALTED:
|
|
|
|
|
/* RFC4880: section 3.7.1.1 and 3.7.1.2 */
|
|
|
|
|
|
|
|
|
|
for (done = 0, i = 0; done < CAST_KEY_LENGTH; i++) {
|
|
|
|
|
unsigned hashsize;
|
|
|
|
|
unsigned j;
|
|
|
|
|
unsigned needed;
|
|
|
|
|
unsigned size;
|
|
|
|
|
uint8_t zero = 0;
|
|
|
|
|
|
|
|
|
|
/* Hard-coded SHA1 for session key */
|
|
|
|
|
pgp_hash_any(&hash, PGP_HASH_SHA1);
|
|
|
|
|
hashsize = pgp_hash_size(key->hash_alg);
|
|
|
|
|
needed = CAST_KEY_LENGTH - done;
|
|
|
|
|
size = MIN(needed, hashsize);
|
|
|
|
|
if ((hashed = calloc(1, hashsize)) == NULL) {
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: bad alloc\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (!hash.init(&hash)) {
|
|
|
|
|
(void) fprintf(stderr, "write_seckey_body: bad alloc\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* preload if iterating */
|
|
|
|
|
for (j = 0; j < i; j++) {
|
|
|
|
|
/*
|
|
|
|
|
* Coverity shows a DEADCODE error on this
|
|
|
|
|
* line. This is expected since the hardcoded
|
|
|
|
|
* use of SHA1 and CAST5 means that it will
|
|
|
|
|
* not used. This will change however when
|
|
|
|
|
* other algorithms are supported.
|
|
|
|
|
*/
|
|
|
|
|
hash.add(&hash, &zero, 1);
|
|
|
|
|
}
|
|
|
|
|
/* preload if iterating */
|
|
|
|
|
for (j = 0; j < i; j++) {
|
|
|
|
|
/*
|
|
|
|
|
* Coverity shows a DEADCODE error on this
|
|
|
|
|
* line. This is expected since the hardcoded
|
|
|
|
|
* use of SHA1 and CAST5 means that it will
|
|
|
|
|
* not used. This will change however when
|
|
|
|
|
* other algorithms are supported.
|
|
|
|
|
*/
|
|
|
|
|
hash.add(&hash, &zero, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key->s2k_specifier == PGP_S2KS_SALTED) {
|
|
|
|
|
hash.add(&hash, key->salt, PGP_SALT_SIZE);
|
|
|
|
|
}
|
|
|
|
|
hash.add(&hash, passphrase, (unsigned)pplen);
|
|
|
|
|
hash.finish(&hash, hashed);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if more in hash than is needed by session key, use
|
|
|
|
|
* the leftmost octets
|
|
|
|
|
*/
|
|
|
|
|
(void) memcpy(&sesskey[i * hashsize],
|
|
|
|
|
hashed, (unsigned)size);
|
|
|
|
|
done += (unsigned)size;
|
|
|
|
|
if (done > CAST_KEY_LENGTH) {
|
|
|
|
|
(void) fprintf(stderr,
|
|
|
|
|
"write_seckey_body: short add\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (key->s2k_specifier == PGP_S2KS_SALTED) {
|
|
|
|
|
hash.add(&hash, key->salt, PGP_SALT_SIZE);
|
|
|
|
|
}
|
|
|
|
|
hash.add(&hash, passphrase, (unsigned)pplen);
|
|
|
|
|
hash.finish(&hash, hashed);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* if more in hash than is needed by session key, use
|
|
|
|
|
* the leftmost octets
|
|
|
|
|
*/
|
|
|
|
|
(void) memcpy(&sesskey[i * hashsize],
|
|
|
|
|
hashed, (unsigned)size);
|
|
|
|
|
done += (unsigned)size;
|
|
|
|
|
if (done > CAST_KEY_LENGTH) {
|
|
|
|
|
(void) fprintf(stderr,
|
|
|
|
|
"write_seckey_body: short add\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* \todo case PGP_S2KS_ITERATED_AND_SALTED: * 8-octet salt
|
|
|
|
|
* value * 1-octet count break;
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
* \todo case PGP_S2KS_ITERATED_AND_SALTED: * 8-octet salt
|
|
|
|
|
* value * 1-octet count break;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
(void) fprintf(stderr,
|
|
|
|
|
"invalid/unsupported s2k specifier %d\n",
|
|
|
|
|
key->s2k_specifier);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
(void) fprintf(stderr,
|
|
|
|
|
"invalid/unsupported s2k specifier %d\n",
|
|
|
|
|
key->s2k_specifier);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* use this session key to encrypt */
|
|
|
|
|
/* use this session key to encrypt */
|
|
|
|
|
|
|
|
|
|
pgp_crypt_any(&crypted, key->alg);
|
|
|
|
|
crypted.set_iv(&crypted, key->iv);
|
|
|
|
|
crypted.set_crypt_key(&crypted, sesskey);
|
|
|
|
|
pgp_encrypt_init(&crypted);
|
|
|
|
|
pgp_crypt_any(&crypted, key->alg);
|
|
|
|
|
crypted.set_iv(&crypted, key->iv);
|
|
|
|
|
crypted.set_crypt_key(&crypted, sesskey);
|
|
|
|
|
pgp_encrypt_init(&crypted);
|
|
|
|
|
|
|
|
|
|
if (pgp_get_debug_level(__FILE__)) {
|
|
|
|
|
hexdump(stderr, "writing: iv=", key->iv, pgp_block_size(key->alg));
|
|
|
|
|
hexdump(stderr, "key= ", sesskey, CAST_KEY_LENGTH);
|
|
|
|
|
(void) fprintf(stderr, "\nturning encryption on...\n");
|
|
|
|
|
}
|
|
|
|
|
pgp_push_enc_crypt(output, &crypted);
|
|
|
|
|
if (pgp_get_debug_level(__FILE__)) {
|
|
|
|
|
hexdump(stderr, "writing: iv=", key->iv, pgp_block_size(key->alg));
|
|
|
|
|
hexdump(stderr, "key= ", sesskey, CAST_KEY_LENGTH);
|
|
|
|
|
(void) fprintf(stderr, "\nturning encryption on...\n");
|
|
|
|
|
}
|
|
|
|
|
pgp_push_enc_crypt(output, &crypted);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (key->pubkey.alg) {
|
|
|
|
|
case PGP_PKA_RSA:
|
|
|
|
@ -477,7 +479,9 @@ write_seckey_body(const pgp_seckey_t *key,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pgp_writer_pop(output);
|
|
|
|
|
if (key->s2k_usage != PGP_S2KU_NONE) {
|
|
|
|
|
pgp_writer_pop(output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|