⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgpkeymisc.c

📁 著名的加密软件的应用于电子邮件中
💻 C
📖 第 1 页 / 共 2 页
字号:
	for (;;) {
		bnExtractBigBytes(bn, buf, start, sizeof(buf));
		i = sizeof(buf);
		start += i;
		do {
			if (buf[--i] == 0) {
				memset(buf, 0, 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(byte *buf, unsigned len, struct BigNum *bn, byte padtype,
	unsigned bytes)
{
	byte tmp[2];

	bnExtractBigBytes(bn, tmp, bytes-2, 2);
	if (tmp[0] != 0) {
		memset(tmp, 0, 2);
		return PGPERR_PK_CORRUPT;
	}

	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) {
			memset(tmp, 0, 2);
			return PGPERR_PK_CORRUPT;
		}
		memset(tmp, 0, 2);

		bytes = bnSearchZeroFromHigh(bn, bytes-2);
		if (bytes-- == 0)
			return PGPERR_PK_CORRUPT;
	} else {
		pgpAssert (padtype==PKCS_PAD_SIGNED);
		/* Signature check, constant padding */
		if (tmp[1] != padtype) {
			memset(tmp, 0, sizeof(tmp));
			return PGPERR_PK_CORRUPT;
		}

		/*
		 * 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 PGPERR_PK_CORRUPT;
		bytes--;
		tmp[1] = 0;
		bnExtractBigBytes(bn, tmp, bytes, 1);
		if (tmp[0] != 0) {
			memset(tmp, 0, sizeof(tmp));
			return PGPERR_PK_CORRUPT;
		}
		/* 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(struct BigNum *bn, byte 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 PGPERR_NOMEM;
	return (int)t+2;
}

/*
 * 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(struct BigNum *bn, byte const *buf, unsigned size,
	struct PgpCfbContext *cfb, unsigned *checksump, int old)
{
	byte tmp[64];	/* This can be any (non-zero) size >= 2 */
	unsigned t, l;

	if (!cfb) {
		int i;

		i = pgpBnGetPlain(bn, buf, size);
		if (i >= 0 && checksump) {
			for (t = 0; t < (unsigned)i; t++)
				*checksump += buf[t];
		}
		return i;
	}

	if (size < 2)
		return 0;
	if (old) {
		/* Length it bits is not encrypted */
		pgpCfbSync(cfb);
		if (checksump)
			*checksump += (unsigned)buf[0] + buf[1];
		t = ((unsigned)buf[0] << 8) + buf[1];
	} else {
		/* Length in bits is encrypted */
		pgpCfbDecrypt(cfb, buf, tmp, 2);
		if (checksump)
			*checksump += (unsigned)tmp[0] + tmp[1];
		t = ((unsigned)tmp[0] << 8) + tmp[1];
	}
	buf += 2;
	t = (t+7)/8;
	if (size < t+2)
		return 0;

	/*
	 * Descrypt and convert in pieces.  It's done from the
	 * most-significnt end to force allocation of the result
	 * number all at once rather than reallocating it bit by bit.
	 */
	size = t;
	while (size) {
		l = size < sizeof(tmp) ? size : sizeof(tmp);

		pgpCfbDecrypt(cfb, buf, tmp, l);
		size -= l;
		buf += l;
		if (bnInsertBigBytes(bn, tmp, size, l) < 0) {
			memset(tmp, 0, sizeof(tmp));
			return PGPERR_NOMEM;
		}

		/* Checksum */
		if (checksump) {
			do {
				*checksump += tmp[--l];
			} while (l);
		}
	}
	memset(tmp, 0, sizeof(tmp));

	return (int)t+2;
}

/*
 * Read the 2-byte simple checksum (as computed above) from the
 * buffer for comparison.  Old-style is unencrypted, new-style is
 * encrypted.
 */
unsigned
pgpChecksumGet(byte const *buf, struct PgpCfbContext *cfb, int old)
{
	byte tmp[2];
	unsigned checksum;

	if (old || !cfb) {
		checksum = ((unsigned)buf[0] << 8) + buf[1];
	} else {
		pgpCfbDecrypt(cfb, buf, tmp, 2);
		checksum = ((unsigned)tmp[0] << 8) + tmp[1];
		memset(tmp, 0, 2);
	}
	return checksum;
}

/*
 * Convert an MPI to a big-endian byte buffer, with a length prefix.
 * Returns number of bytes put into buffer.
 */
unsigned
pgpBnPutPlain(struct BigNum const *bn, byte *buf)
{
	unsigned t;

	t = bnBits(bn);
	buf[0] = (byte)(t>>8 & 255);
	buf[1] = (byte)(t & 255);
	t = (t+7)/8;
	bnExtractBigBytes(bn, buf+2, 0, t);
	return t+2;
}

/*
 * 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(struct BigNum const *bn, byte *buf,
	struct 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);
			pgpCfbEncrypt(cfb, buf+2, buf+2, t-2);
		} else {
			pgpCfbEncrypt(cfb, buf, buf, t);
		}
	}
	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, byte *buf, struct PgpCfbContext *cfb,
	int old)
{
	buf[0] = (byte)(checksum>>8 & 255);
	buf[1] = (byte)(checksum & 255);
	if (cfb && !old)
		pgpCfbEncrypt(cfb, buf, buf, 2);
}

/*
 * 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(struct BigNum *bn, struct PgpRandomContext const *rc,
	     unsigned bits, byte high, byte low, unsigned effective)
{
	unsigned char buf[64];
	unsigned bytes;
	unsigned l;
	int err;

	bnSetQ(bn, 0);

	/* Get high random bits */
	bytes = (bits+7) / 8;
	l = bytes < sizeof(buf) ? bytes : sizeof(buf);
	pgpRandomGetBytesEntropy(rc, buf, l, effective);

	/* Mask off excess high bits */
	buf[0] &= 255 >> (-bits & 7);
	/* Merge in specified high bits */
	buf[0] |= high >> (-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);
		pgpRandomGetBytesEntropy(rc, buf, l, 0);
	}

	/* Burn and return */
	memset(buf, 0, 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(byte const *buf, unsigned size, int n, ...)
{
	va_list ap;
	unsigned nb;
	unsigned off;
	unsigned *poff;

	va_start (ap, n);
	if (size < 2U*n)
		return PGPERR_KEY_SHORT;
	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 PGPERR_KEY_MPI; /* 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 PGPERR_KEY_SHORT;
		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.)
 */
int
pgpCipherSetup(byte const *buf, unsigned len, char const *phrase, size_t plen,
	struct PgpEnv const *env, struct PgpCfbContext **cfbp)
{
	struct PgpCipher const *cipher;
	struct PgpStringToKey *s2k;
	unsigned alg;
	int alglen;
	byte key[PGP_CIPHER_MAXKEYSIZE];

	/* First things first, in case of error... */
	*cfbp = NULL;

	if (len < 1)
		return PGPERR_KEY_SHORT;

	alg = buf[0] & 255;

	if (!alg)	/* The key isn't encrypted; just read it in */
		return 1;

	if (alg == 255) {
		/* New style, with a separate string-to-key */

		if (len == 1)
			return PGPERR_KEY_SHORT;
		alg = buf[1];
		alglen = pgpS2Kdecode(&s2k, env, buf+2, len-2);
		if (alglen < 0)
			return alglen;
		alglen += 2;
		if (len < (unsigned)alglen)
			return PGPERR_KEY_SHORT;
	} else {
		/* Old-style string-to-key */
		s2k = pgpS2Ksimple(env, pgpHashByNumber(PGP_HASH_MD5));
		if (!s2k)
			return PGPERR_NOMEM;
		alglen = 1;
	}
	/* Okay now, do the conversion */
	cipher = pgpCipherByNumber(alg);
	if (!cipher) {
		pgpS2Kdestroy(s2k);
		return PGPERR_BAD_CIPHERNUM;
	}
	if (len < alglen + cipher->blocksize) {
		pgpS2Kdestroy(s2k);
		return PGPERR_KEY_SHORT;
	}
	*cfbp = pgpCfbCreate(cipher);
	if (!*cfbp) {
		pgpS2Kdestroy(s2k);
		return PGPERR_NOMEM;
	}
	pgpAssert(cipher->keysize <= sizeof(key));
	pgpStringToKey(s2k, phrase, plen, key, cipher->keysize);
	pgpCfbInit(*cfbp, key, buf + alglen);
	memset(key, 0, sizeof(key));
	pgpS2Kdestroy(s2k);

	return alglen + cipher->blocksize;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -