|
|
@ -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; |
|
|
|
} |
|
|
|