void genkey(const Memblock &string, uint8_t *key, uint32_t length) const
		{
			pgpry_SHA_CTX ctx;
			uint32_t numHashes = (length + SHA_DIGEST_LENGTH - 1) / SHA_DIGEST_LENGTH;

			for (uint32_t i = 0; i < numHashes; i++) {
				pgpry_SHA1_Init(&ctx);
				for (uint32_t j = 0; j < i; j++) {
					pgpry_SHA1_Update(&ctx, "\0", 1);
				}
				pgpry_SHA1_Update(&ctx, string.data, string.length);
				pgpry_SHA1_Final(key + (i * SHA_DIGEST_LENGTH), &ctx);
			}
		}
		void genkey(const Memblock &string, uint8_t *key, uint32_t length) const
		{
			pgpry_SHA_CTX ctx;
			uint32_t numHashes = (length + SHA_DIGEST_LENGTH - 1) / SHA_DIGEST_LENGTH;

			// TODO: This is not very efficient with multiple hashes
			for (uint32_t i = 0; i < numHashes; i++) {
				pgpry_SHA1_Init(&ctx);
				for (uint32_t j = 0; j < i; j++) {
					pgpry_SHA1_Update(&ctx, "\0", 1);
				}

				// Find multiplicator
				int32_t tl = string.length + 8;
				int32_t mul = 1;
				while (mul < tl && ((64 * mul) % tl)) {
					++mul;
				}

				// Try to feed the hash function with 64-byte blocks
				const int32_t bs = mul * 64;
				assert(bs <= KEYBUFFER_LENGTH);
				uint8_t *bptr = m_keybuf + tl;
				int32_t n = bs / tl;
				memcpy(m_keybuf + 8, string.data, string.length);
				while (n-- > 1) {
					memcpy(bptr, m_keybuf, tl);
					bptr += tl;
				}
				n = m_count / bs;
				while (n-- > 0) {
					pgpry_SHA1_Update(&ctx, m_keybuf, bs);
				}
				pgpry_SHA1_Update(&ctx, m_keybuf, m_count % bs);

				pgpry_SHA1_Final(key + (i * SHA_DIGEST_LENGTH), &ctx);
			}
		}
Exemple #3
0
// Checks if the given password is valid
bool Tester::check(const Memblock &mblock)
{
	const String2Key &s2k = m_key.string2Key();
	int32_t tmp = 0;

	// Generate key from password
	s2k.generateKey(mblock, m_keydata, m_keySize);

	// Decrypt first data block in order to check the first two bits of
	// the MPI. If they are correct, there's a good chance that the
	// password is correct, too.
#if 1
	memcpy(m_ivec, s2k.ivec(), m_blockSize);
	switch (m_cipher) {
		case CryptUtils::CIPHER_CAST5: {
			CAST_KEY ck;
			CAST_set_key(&ck, m_keySize, m_keydata);
			CAST_cfb64_encrypt(m_in, m_out, CAST_BLOCK, &ck, m_ivec, &tmp, CAST_DECRYPT);
		}
		break;
		case CryptUtils::CIPHER_BLOWFISH: {
			BF_KEY ck;
			BF_set_key(&ck, m_keySize, m_keydata);
			BF_cfb64_encrypt(m_in, m_out, BF_BLOCK, &ck, m_ivec, &tmp, BF_DECRYPT);
		}
		break;
		case CryptUtils::CIPHER_AES128:
		case CryptUtils::CIPHER_AES192:
		case CryptUtils::CIPHER_AES256: {
			AES_KEY ck;
			AES_set_encrypt_key(m_keydata, m_keySize * 8, &ck);
			AES_cfb128_encrypt(m_in, m_out, AES_BLOCK_SIZE, &ck, m_ivec, &tmp, AES_DECRYPT);
		}
		break;

		default:
			break;
	}

	uint32_t num_bits = ((m_out[0] << 8) | m_out[1]);
	if (num_bits < MIN_BN_BITS || num_bits > m_bits) {
		return false;
	}
#endif

	// Decrypt all data
	memcpy(m_ivec, s2k.ivec(), m_blockSize);
	tmp = 0;
	switch (m_cipher) {
		case CryptUtils::CIPHER_CAST5: {
			CAST_KEY ck;
			CAST_set_key(&ck, m_keySize, m_keydata);
			CAST_cfb64_encrypt(m_in, m_out, m_datalen, &ck, m_ivec, &tmp, CAST_DECRYPT);
		}
		break;
		case CryptUtils::CIPHER_BLOWFISH: {
			BF_KEY ck;
			BF_set_key(&ck, m_keySize, m_keydata);
			BF_cfb64_encrypt(m_in, m_out, m_datalen, &ck, m_ivec, &tmp, BF_DECRYPT);
		}
		break;
		case CryptUtils::CIPHER_AES128:
		case CryptUtils::CIPHER_AES192:
		case CryptUtils::CIPHER_AES256: {
			AES_KEY ck;
			AES_set_encrypt_key(m_keydata, m_keySize * 8, &ck);
			AES_cfb128_encrypt(m_in, m_out, m_datalen, &ck, m_ivec, &tmp, AES_DECRYPT);
		}
		break;

		default:
			break;
	}

	// Verify
	bool checksumOk = false;
	switch (s2k.usage()) {
		case 254: {
			uint8_t checksum[SHA_DIGEST_LENGTH];
			pgpry_SHA_CTX ctx;
			pgpry_SHA1_Init(&ctx);
			pgpry_SHA1_Update(&ctx, m_out, m_datalen - SHA_DIGEST_LENGTH);
			pgpry_SHA1_Final(checksum, &ctx);
			if (memcmp(checksum, m_out + m_datalen - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH) == 0) {
				checksumOk = true;
			}
		} break;

		case 0:
		case 255: {
			uint16_t sum = 0;
			for (uint32_t i = 0; i < m_datalen - 2; i++) {
				sum += m_out[i];
			}
			if (sum == ((m_out[m_datalen - 2] << 8) | m_out[m_datalen - 1])) {
				checksumOk = true;
			}
		} break;

		default:
			break;
	}

	// If the checksum is ok, try to parse the first MPI of the private key
	if (checksumOk) {
		BIGNUM *b = NULL;
		uint32_t blen = (num_bits + 7) / 8;
		if (blen < m_datalen && ((b = BN_bin2bn(m_out + 2, blen, NULL)) != NULL)) {
			BN_free(b);
			return true;
		}
	}

	return false;
}
Exemple #4
0
// Checks if the given password is valid
bool Tester::check(const Memblock &mblock)
{
	const String2Key &s2k = m_key.string2Key();
	int32_t tmp = 0;

	// Generate key from password
	s2k.generateKey(mblock, m_keydata, m_keySize);

	// Decrypt first data block in order to check the first two bits of
	// the MPI. If they are correct, there's a good chance that the
	// password is correct, too.
#if 1
	memcpy(m_ivec, s2k.ivec(), m_blockSize);
	if (m_key.version() < 4) {
		// Prior to V4, MPI lengths are unencrypted.
		memcpy(m_out, m_in, 2);
		m_key.decrypt(&m_in[2], &m_out[2], m_blockSize, m_keydata, m_keySize, m_ivec, &tmp);
	} else {
		m_key.decrypt(m_in, m_out, m_blockSize, m_keydata, m_keySize, m_ivec, &tmp);
	}

	uint32_t num_bits = ((m_out[0] << 8) | m_out[1]);
	if (num_bits < MIN_BN_BITS || num_bits > m_bits ||
	    (num_bits % 8 != BN_num_bits_word(m_out[2]) % 8))
	{
		return false;
	}
#endif

	// Decrypt all data
	memcpy(m_ivec, s2k.ivec(), m_blockSize);
	if (m_key.version() < 4) {
		// V3 keys are RSA only according to [5.5.3].
		if (CryptUtils::PKA_RSA_ENCSIGN != m_key.algorithm()) {
			throw Utils::strprintf("Unexpected V3 algorithm: %d",
				m_key.algorithm());
		}

		// Prior to V4, the four RSA MPIs were encrypted separately.
		uint32_t ofs = 0;
		for (uint32_t i = 0; i != 4; ++i) {
			memcpy(&m_out[ofs], &m_in[ofs], 2);
			uint32_t len = (((m_out[ofs] << 8) | m_out[1 + ofs]) + 7) / 8;
			ofs += 2;

			if (m_datalen < ofs + len) {
				throw "Insufficient data length";
			}
			tmp = 0;
			m_key.decrypt(&m_in[ofs], &m_out[ofs], len, m_keydata, m_keySize, m_ivec, &tmp);
			ofs += len;
		}

		// Copy checksum.
		memcpy(&m_out[ofs], &m_in[ofs], 2);
		ofs += 2;
		if (ofs != m_datalen) {
			throw "Data length mismatch";
		}
	} else {
		tmp = 0;
		m_key.decrypt(m_in, m_out, m_datalen, m_keydata, m_keySize, m_ivec, &tmp);
	}

	// Verify
	bool checksumOk = false;
	switch (s2k.usage()) {
		case 254: {
			uint8_t checksum[SHA_DIGEST_LENGTH];
			pgpry_SHA_CTX ctx;
			pgpry_SHA1_Init(&ctx);
			pgpry_SHA1_Update(&ctx, m_out, m_datalen - SHA_DIGEST_LENGTH);
			pgpry_SHA1_Final(checksum, &ctx);
			if (memcmp(checksum, m_out + m_datalen - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH) == 0) {
				checksumOk = true;
			}
		} break;

		default: {
			uint16_t sum = 0;
			for (uint32_t i = 0; i < m_datalen - 2; i++) {
				sum += m_out[i];
			}
			if (sum == ((m_out[m_datalen - 2] << 8) | m_out[m_datalen - 1])) {
				checksumOk = true;
			}
		} break;
	}

	// If the checksum is ok, verify the secret key equations.
	return checksumOk && m_key.verify(m_out, m_datalen - 2);
}