📄 pgpkeymisc.c
字号:
return kPGPError_OutOfMemory;
} else {
/* Old <= 2.2 format - no DER prefix */
len -= sizeof(MD5_prefix);
in += sizeof(MD5_prefix);
if (len+3+1 > bytes)
return kPGPError_PublicKeyTooSmall; /* won't fit */
if (bnInsertBigBytes(bn, &pgp22_MD5_byte, bytes-1, 1)
< 0 ||
bnInsertBigBytes(bn, in, bytes-len-2, len) < 0 ||
onesPad(bn, bytes-len-2, 1) < 0 ||
bnInsertBigBytes(bn, &padtype, 0, 1) < 0)
return kPGPError_OutOfMemory;
}
}
return 0;
}
/*
* Searches bytes, beginning with start-1 and progressing to 0,
* until one that is not 0xff is found. The idex of the last 0xff
* byte is returned (or start if start-1 is not 0xff.)
*/
static unsigned
bnSearchNonOneFromHigh(BigNum const *bn, unsigned start)
{
PGPByte buf[16]; /* Size is arbitrary */
unsigned l;
unsigned i;
while (start) {
l = start < sizeof(buf) ? start : sizeof(buf);
start -= l;
bnExtractBigBytes(bn, buf, start, l);
for (i = 0; i < l; i++) {
if (buf[i] != 0xff) {
pgpClearMemory( buf, sizeof(buf));
return start + l - i;
}
}
}
/* Nothing found */
pgpClearMemory( buf, sizeof(buf));
return 0;
}
/*
* Searches bytes, beginning with start and going up (towards more
* significant bytes), until one that is not 0xff is found. Since the
* input number is finite, there must be zeros eventually.
* The index of the first non-0xff byte is returned.
*/
static unsigned
bnSearchNonOneFromLow(BigNum const *bn, unsigned start)
{
PGPByte buf[16]; /* Size is arbitrary */
unsigned i;
for (;;) {
bnExtractBigBytes(bn, buf, start, sizeof(buf));
i = sizeof(buf);
start += i;
do {
if (buf[--i] != 0xff) {
pgpClearMemory( buf, sizeof(buf));
return start - i - 1;
}
} while (i);
}
/*NOTREACHED*/
}
/*
* Searches bytes, beginning with start-1 and progressing to 0,
* until finding one that is zero, or the end of the array.
* The index of the last non-zero byte is returned (0 if the array
* is all non-zero, or start if start-1 is zero).
*/
static unsigned
bnSearchZeroFromHigh(BigNum const *bn, unsigned start)
{
PGPByte buf[16]; /* Size is arbitrary */
unsigned l;
unsigned i;
while (start) {
l = start < sizeof(buf) ? start : sizeof(buf);
start -= l;
bnExtractBigBytes(bn, buf, start, l);
for (i = 0; i < l; i++) {
if (buf[i] == 0) {
pgpClearMemory( buf, sizeof(buf));
return start + l - i;
}
}
}
/* Nothing found */
pgpClearMemory( buf, sizeof(buf));
return 0;
}
/*
* Searches bytes, beginning with start and going up (towards more
* significant bytes), until one that is zero is found. Since the
* input number is finite, there must be zeros eventually.
* The index of the first zero byte is returned.
*/
static unsigned
bnSearchZeroFromLow(BigNum const *bn, unsigned start)
{
PGPByte buf[16]; /* Size is arbitrary */
unsigned i;
for (;;) {
bnExtractBigBytes(bn, buf, start, sizeof(buf));
i = sizeof(buf);
start += i;
do {
if (buf[--i] == 0) {
pgpClearMemory( buf, sizeof(buf));
return start - i - 1;
}
} while (i);
}
/*NOTREACHED*/
}
/*
* Performs a PKCS unpack operation. Returns a prefix of the unwrapped
* data in the given buf. Returns the length of the untruncated
* data, which may exceed "len". Returns <0 on error.
*
* For the constant-padding (signature checking) case,
* it recongizes the PGP 2.2 format, but not in all its generality;
* only the one case (framing byte = 1, length = 16) which was ever
* generated. It fakes the DER prefix in that case.
*/
int
pgpPKCSUnpack(PGPByte *buf, unsigned len, BigNum *bn, PGPByte padtype,
unsigned bytes)
{
PGPByte tmp[2];
bnExtractBigBytes(bn, tmp, bytes-2, 2);
if (tmp[0] != 0) {
pgpClearMemory( tmp, 2);
return kPGPError_CorruptData;
}
if (padtype == PKCS_PAD_ENCRYPTED) {
/* Decryption case, random padding */
/* Special case: PGP <= 2.2 hack */
bnExtractBigBytes(bn, tmp, 0, 1);
if (tmp[1] == 1 && tmp[0] == padtype &&
bnSearchZeroFromLow(bn, 1) == bytes-1-1-16-2-1)
{
/* Aha, it's PGP <= 2.2 */
if (len > 1+16+2)
len = 1+16+2;
bnExtractBigBytes(bn, buf, bytes-1-len, len);
return 1+16+2;
}
/* Okay, assume it's PKCS.1 */
if (tmp[1] != 2) {
pgpClearMemory( tmp, 2);
return kPGPError_CorruptData;
}
pgpClearMemory( tmp, 2);
bytes = bnSearchZeroFromHigh(bn, bytes-2);
if (bytes-- == 0)
return kPGPError_CorruptData;
} else {
pgpAssert (padtype==PKCS_PAD_SIGNED);
/* Signature check, constant padding */
if (tmp[1] != padtype) {
pgpClearMemory( tmp, sizeof(tmp));
return kPGPError_CorruptData;
}
/*
* Special-case hack: is is PGP <= 2.2 format? This is
* identified by a least significant byte of 1, a byte
* of 0 between the 16-byte MD5 hash and the padding,
* and all ones padding.
*/
bnExtractBigBytes(bn, tmp, 0, 1); /* Should be 1 if <= 2.2 */
bnExtractBigBytes(bn, tmp+1, bytes-19, 1); /* zero if <= 2.2 */
if (tmp[0] == padtype && tmp[1] == 0 &&
bnSearchNonOneFromLow(bn, 1) == bytes-19)
{
/* Aha, it's PGP <= 2.2 - fake up the DER prefix */
if (len <= sizeof(MD5_prefix)) {
memcpy(buf, MD5_prefix, len);
} else {
memcpy(buf, MD5_prefix, sizeof(MD5_prefix));
buf += sizeof(MD5_prefix);
len -= sizeof(MD5_prefix);
if (len > 16)
len = 16;
bnExtractBigBytes(bn, buf, bytes-2-len, len);
}
return 16 + sizeof(MD5_prefix);
}
/* Okay, assume it's PKCS format thing. */
bytes = bnSearchNonOneFromHigh(bn, bytes-2);
if (bytes < 1)
return kPGPError_CorruptData;
bytes--;
tmp[1] = 0;
bnExtractBigBytes(bn, tmp, bytes, 1);
if (tmp[0] != 0) {
pgpClearMemory( tmp, sizeof(tmp));
return kPGPError_CorruptData;
}
/* Note: tmp isn't secret any more because it's a constant! */
}
/* Success! Return the data */
if (len > bytes)
len = bytes;
bnExtractBigBytes(bn, buf, bytes-len, len);
return bytes;
}
/*
* Convert a big-endian byte buffer (with bit-count prefix) to an MPI.
* Returns number of bytes read from buffer, or <= 0 on error.
* (Returns 0 if the buffer is too short.)
*/
int
pgpBnGetPlain(BigNum *bn, PGPByte const *buf, unsigned size)
{
unsigned t;
if (size < 2)
return 0;
t = ((unsigned)buf[0] << 8) + buf[1];
t = (t+7)/8;
if (size < t+2)
return 0;
if (bnInsertBigBytes(bn, buf+2, 0, t) < 0)
return kPGPError_OutOfMemory;
return (int)t+2;
}
/* Read start of an X.509 object */
PGPByte
pgpBnX509TagLen(PGPByte const **buf, PGPUInt32 *length)
{
PGPByte tag = *(*buf)++ & 0x1f;
PGPUInt32 len = *(*buf)++;
if (len & 0x80) {
PGPUInt32 lenlen = len & 0x7f;
len = 0;
while (lenlen--) {
len <<= 8;
len |= *(*buf)++;
}
}
*length = len;
return tag;
}
PGPUInt32
pgpBnX509LenLen(PGPUInt32 length)
{
if (length < 0x80)
return 1;
if (length < 0x100)
return 2;
if (length < 0x10000)
return 3;
if (length < 0x1000000)
return 4;
return 5;
}
/*
* Convert a big-endian byte buffer to an MPI. PGP format uses a
* bitcount prefix.
* Returns number of bytes read from buffer, or <= 0 on error.
* (Returns 0 if the buffer is too short.)
*/
int
pgpBnGetFormatted(BigNum *bn, PGPByte const *buf, unsigned size,
unsigned modbytes, PGPPublicKeyMessageFormat format)
{
unsigned extra = 0;
if (format == kPGPPublicKeyMessageFormat_PGP) {
return pgpBnGetPlain( bn, buf, size );
}
if (format == kPGPPublicKeyMessageFormat_X509) {
PGPUInt32 len;
PGPByte const *bp = buf;
if (pgpBnX509TagLen(&buf, &len) != X509_TAG_INTEGER)
return kPGPError_MalformedKeyComponent;
extra = buf - bp;
size -= extra;
if (len > size)
return kPGPError_MalformedKeyComponent;
modbytes = len;
} else {
pgpAssert( format == kPGPPublicKeyMessageFormat_PKCS1 ||
format == kPGPPublicKeyMessageFormat_IKE );
}
if (size < modbytes)
return 0;
if (bnInsertBigBytes(bn, buf, 0, modbytes) < 0)
return kPGPError_OutOfMemory;
return (int)(modbytes + extra);
}
/*
* Helper function for key unlocking.
* Convert a big-endian byte buffer to an MPI, with optional decryption and
* checksums. Accepts cfb == NULL to mean "unencrypted".
* Returns number of bytes read from buffer, or <= 0 on error.
* (Returns 0 if the buffer is too short.)
*
* If "old" is true, this does it in the PGP 2.x way, where the length
* of the data is unencrypted and the CFB is resynced each step.
* If "old" is false, this assumes that just everything is encrypted
* and
*/
int
pgpBnGet(BigNum *bn, PGPByte const *buf, unsigned size,
PGPCFBContext *cfb, unsigned *checksump, int old)
{
PGPByte tmp[64]; /* This can be any (non-zero) size >= 2 */
unsigned t, l;
if (!cfb) {
int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -