📄 pgpkeymisc.c
字号:
pgpClearMemory( tmp, sizeof(tmp));
return kPGPError_OutOfMemory;
}
/* Checksum */
if (state)
PGPContinueHash( state, tmp, l );
}
pgpClearMemory( tmp, sizeof(tmp));
return (int)t+2;
}
/*
* Read checksum (as computed above) or hash (SHA1) from the buffer
* for comparison. Input data can be encrypted, in this case cfb
* object must be provided.
*
* alg0 is the first octet indicating string-to-key
* usage conventions from Section 5.5.3 Secret Key Packet Formats, RFC 2440.
*
* Returns number of bytes it reads from buf or writes into out.
* Can be called with everything but alg0 set to NULL to get the checksum length.
*/
unsigned
pgpChecksumGet(PGPByte const *buf, PGPCFBContext *cfb, PGPByte alg0,
PGPHashContextRef state, PGPByte *out)
{
PGPSize hashSize = 0;
pgpAssert( state );
PGPGetHashSize( state, &hashSize );
if( out!=NULL ) {
if (alg0==0 || !cfb) {
out[0] = buf[0];
out[1] = buf[1];
} else {
pgpCFBDecryptInternal(cfb, buf, hashSize, out);
}
}
return hashSize;
}
/*
* Convert an MPI to a big-endian byte buffer, with a length prefix.
* Returns number of bytes put into buffer.
*/
unsigned
pgpBnPutPlain(BigNum const *bn, PGPByte *buf)
{
unsigned t;
t = bnBits(bn);
buf[0] = (PGPByte)(t>>8 & 255);
buf[1] = (PGPByte)(t & 255);
t = (t+7)/8;
bnExtractBigBytes(bn, buf+2, 0, t);
return t+2;
}
/*
* Convert an MPI to a big-endian byte buffer. PGP format uses a
* length prefix.
* Returns number of bytes put into buffer.
*/
unsigned
pgpBnPutFormatted(BigNum const *bn, PGPByte *buf,
unsigned modbytes, PGPPublicKeyMessageFormat format)
{
unsigned extra = 0;
if (format == kPGPPublicKeyMessageFormat_PGP) {
return pgpBnPutPlain( bn, buf );
}
if (format == kPGPPublicKeyMessageFormat_X509) {
/* Insert integer prefix in DER encoding */
PGPUInt32 lenlen;
PGPUInt32 len;
if (bnBits(bn) == 8*modbytes)
modbytes += 1;
len = modbytes;
*buf++ = X509_TAG_INTEGER;
++extra;
lenlen = pgpBnX509LenLen(len);
if (--lenlen == 0) {
*buf++ = len;
++extra;
} else {
*buf++ = 0x80 | lenlen;
++extra;
len <<= 8 * (4-lenlen);
while (lenlen--) {
*buf++ = (PGPByte)(len >> 24);
++extra;
len <<= 8;
}
}
}
bnExtractBigBytes(bn, buf, 0, modbytes);
return modbytes + extra;
}
/*
* Helper function for ChangeLock.
* Convert an MPI to a big-endian byte buffer, with optional encryption and
* checksums. Accepts cfb == NULL to mean "unencrypted".
* Returns number of bytes put into buffer.
*/
unsigned
pgpBnPut(BigNum const *bn, PGPByte *buf,
PGPCFBContext *cfb, unsigned *checksump, int old)
{
unsigned t, u;
t = pgpBnPutPlain(bn, buf);
if (checksump)
for (u = 0; u < t; u++)
*checksump += buf[u];
if (cfb) {
if (old) {
PGPCFBSync(cfb);
pgpCFBEncryptInternal(cfb, buf+2, t-2, buf+2);
} else {
pgpCFBEncryptInternal(cfb, buf, t, buf);
}
}
return t;
}
/*
* Write the 2-byte simple checksum (as computed above) to the
* buffer for comparison. Old-style is unencrypted, new-style is
* encrypted.
*/
void
pgpChecksumPut(unsigned checksum, PGPByte *buf, PGPCFBContext *cfb,
int old)
{
buf[0] = (PGPByte)(checksum>>8 & 255);
buf[1] = (PGPByte)(checksum & 255);
if (cfb && !old)
pgpCFBEncryptInternal(cfb, buf, 2, buf);
}
#if 0
/*
* Write the checksum or hash to the buffer for comparison.
* Old-style is unencrypted and indicated by passing NULL as cfb.
*/
unsigned pgpChecksumPutEx( const PGPByte *checksum, PGPByte *buf, PGPCFBContext *cfb, PGPByte alg0 )
{
unsigned size = pgpChecksumGetEx(NULL, NULL, alg0, NULL);
if (cfb != NULL)
pgpCFBEncryptInternal(cfb, checksum, size, buf);
else
pgpCopyMemory( checksum, buf, size );
return size;
}
#endif
/*
* Generate a random bignum of the specified length, with the given
* high and low 8 bits. "High" is merged into the high 8 bits of the
* number. For example, set it to 0x80 to ensure that the number is
* exactly "bits" bits long (i.e. 2^(bits-1) <= bn < 2^bits).
* "Low" is merged into the low 8 bits. For example, set it to
* 1 to ensure that you generate an odd number.
*/
int
pgpBnGenRand(BigNum *bn, PGPRandomContext const *rc,
unsigned bits, PGPByte high, PGPByte low, unsigned effective)
{
unsigned char buf[64];
unsigned bytes;
unsigned l;
unsigned leffective;
int err;
bnSetQ(bn, 0);
/* Get high random bits */
bytes = (bits+7) / 8;
l = bytes < sizeof(buf) ? bytes : sizeof(buf);
leffective = pgpMin(l*8, effective);
pgpRandomGetBytesEntropy(rc, buf, l, leffective);
effective -= leffective;
/* Mask off excess high bits */
buf[0] &= 255 >> (-(int)bits & 7);
/* Merge in specified high bits */
buf[0] |= high >> (-(int)bits & 7);
if (bits & 7)
buf[1] |= high << (bits & 7);
for (;;) {
bytes -= l;
if (!bytes) /* Last word - merge in low bits */
buf[l-1] |= low;
err = bnInsertBigBytes(bn, buf, bytes, l);
if (!bytes || err < 0)
break;
l = bytes < sizeof(buf) ? bytes : sizeof(buf);
leffective = pgpMin(l*8, effective);
pgpRandomGetBytesEntropy(rc, buf, l, leffective);
effective -= leffective;
}
/* Burn and return */
pgpClearMemory( buf, sizeof(buf));
return err;
}
/*
* Parse a buffer containing n mpi format numbers (two bytes of length in bits,
* followed by data). Make sure data is well formed and doesn't exceed
* buffer length. Take n pointers to offsets where the n numbers start
* (pointers may be null but must not be left off arg list).
* Return offset past last value, or negative for error.
*/
int
pgpBnParse(PGPByte const *buf, unsigned size, int n, ...)
{
va_list ap;
unsigned nb;
unsigned off;
unsigned *poff;
va_start (ap, n);
if (size < 2U*n)
return kPGPError_KeyPacketTruncated;
off = 0;
while (n--) {
poff = va_arg(ap, unsigned *);
nb = ((unsigned)buf[0+off] << 8) + buf[1+off];
if (!nb || buf[2+off] >> ((nb-1) & 7) != 1)
return kPGPError_MalformedKeyComponent; /* Bad bit length */
nb = (nb+7)/8;
/* Need nb+2 bytes for this, plus 2*n for remainder */
if (size-off < nb + 2 + 2*n)
return kPGPError_KeyPacketTruncated;
if (poff)
*poff = off;
off += nb+2;
}
va_end (ap);
return off;
}
/*
* Given a cipher algorithm descriptor in (buf,len) and a passphrase,
* initialize the passed-in PGPCFBContext pointer and return the
* number of bytes of descriptor used, or <0 on error. (In which
* case *cfbp is NULL.) If hashedPhrase is true, the passphrase has
* already been hashed using the s2k object and we use it literally
* as the key.
*/
int
pgpCipherSetup(
PGPByte const *buf, unsigned len, char const *phrase, PGPSize plen,
PGPBoolean hashedPhrase, PGPBoolean twofishRetry, PGPContextRef context,
PGPCFBContext **cfbp)
{
PGPCipherVTBL const *cipher;
PGPStringToKey *s2k;
unsigned alg;
int alglen;
PGPByte key[PGP_CIPHER_MAXKEYSIZE];
/* Sanity check on lengths, otherwise we take forever */
pgpAssert( plen < 0x10000U );
pgpAssert( len < 0x10000U );
/* First things first, in case of error... */
*cfbp = NULL;
if (len < 1)
return kPGPError_KeyPacketTruncated;
alg = buf[0] & 255;
if (!alg) /* The key isn't encrypted; just read it in */
return 1;
if (alg == 0xff || alg == 0xfe) {
/* New style, with a separate string-to-key */
if (len == 1)
return kPGPError_KeyPacketTruncated;
alg = buf[1];
alglen = pgpS2Kdecode(&s2k, context, buf+2, len-2);
if (alglen < 0)
return alglen;
alglen += 2;
if (len < (unsigned)alglen)
return kPGPError_KeyPacketTruncated;
} else {
/* Old-style string-to-key */
s2k = pgpS2Ksimple(context, pgpHashByNumber(kPGPHashAlgorithm_MD5));
if (!s2k)
return kPGPError_OutOfMemory;
alglen = 1;
}
if( alg == kPGPCipherAlgorithm_Twofish256 && twofishRetry )
{
/* Had a mis-implementation of Twofish on bigendian machines, so for
* backwards compatibility we must retry unlocking failures using
* the old, bad algorithm
*/
alg = kPGPCipherAlgorithm_BadTwofish256;
}
/* Okay now, do the conversion */
cipher = pgpCipherGetVTBL( (PGPCipherAlgorithm)alg);
if (!cipher) {
pgpS2Kdestroy(s2k);
return kPGPError_BadCipherNumber;
}
if (len < alglen + cipher->blocksize) {
pgpS2Kdestroy(s2k);
return kPGPError_KeyPacketTruncated;
}
*cfbp = pgpCFBCreate( PGPPeekContextMemoryMgr( context ), cipher);
if (!*cfbp) {
pgpS2Kdestroy(s2k);
return kPGPError_OutOfMemory;
}
pgpAssert(cipher->keysize <= sizeof(key));
if (hashedPhrase) {
pgpCopyMemory (phrase, key, plen);
} else {
pgpStringToKey(s2k, phrase, plen, key, cipher->keysize);
}
PGPInitCFB(*cfbp, key, buf + alglen);
pgpClearMemory( key, sizeof(key));
pgpS2Kdestroy(s2k);
return alglen + cipher->blocksize;
}
/*
* Helper function: seed a RandomContext from a BigNum.
* Be very sure to leave nothing in memory!
*/
void
pgpRandomBnSeed(PGPRandomContext const *rc, BigNum const *bn)
{
PGPByte buf[32]; /* Big enough for 99.9% of all keys */
unsigned bytes = (bnBits(bn) + 7)/8;
unsigned off = 0;
while (bytes > sizeof(buf)) {
bnExtractLittleBytes(bn, buf, off, sizeof(buf));
pgpRandomAddBytes(rc, buf, sizeof(buf));
bytes -= sizeof(buf);
off += sizeof(buf);
}
bnExtractLittleBytes(bn, buf, off, bytes);
pgpRandomAddBytes(rc, buf, bytes);
pgpClearMemory( buf, sizeof(buf));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -