You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
11 KiB
C++
378 lines
11 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include "CrySystem_precompiled.h"
|
|
#include "System.h"
|
|
#include "ZipEncrypt.h"
|
|
#include "smartptr.h"
|
|
#include "CryZlib.h"
|
|
|
|
#ifdef INCLUDE_LIBTOMCRYPT
|
|
|
|
#define mp_count_bits(a) ltc_mp.count_bits(a)
|
|
#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a)
|
|
|
|
void ZipEncrypt::Init(const uint8* pKeyData, uint32 keyLen)
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION;
|
|
|
|
ltc_mp = ltm_desc;
|
|
register_hash (&sha1_desc);
|
|
register_hash (&sha256_desc);
|
|
|
|
register_cipher (&twofish_desc);
|
|
|
|
int prng_idx = register_prng(&yarrow_desc) != -1;
|
|
assert(prng_idx != -1);
|
|
rng_make_prng(128, find_prng("yarrow"), &g_yarrow_prng_state, NULL);
|
|
|
|
int importReturn = rsa_import(pKeyData, (unsigned long)keyLen, &g_rsa_key_public_for_sign);
|
|
if (CRYPT_OK != importReturn)
|
|
{
|
|
#if !defined(_RELEASE)
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "RSA Public Key failed to initialize. Returned %d", importReturn);
|
|
#endif //_RELEASE
|
|
}
|
|
}
|
|
|
|
bool ZipEncrypt::StartStreamCipher(unsigned char key[16], unsigned char IV[16], symmetric_CTR* pCTR, const unsigned int offset)
|
|
{
|
|
int err;
|
|
|
|
int cipher_idx = find_cipher(STREAM_CIPHER_NAME);
|
|
if (cipher_idx < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
err = ctr_start(cipher_idx, IV, key, 16, 0, CTR_COUNTER_LITTLE_ENDIAN, pCTR);
|
|
if (err != CRYPT_OK)
|
|
{
|
|
//printf("ctr_start error: %s\n",error_to_string(errno));
|
|
return false;
|
|
}
|
|
|
|
// Seek forward into the stream cipher by offset bytes
|
|
unsigned int offset_blocks = offset / pCTR->blocklen;
|
|
unsigned int offset_remaining = offset - (offset_blocks * pCTR->blocklen);
|
|
|
|
if (offset_blocks > 0)
|
|
{
|
|
SwapEndian((uint32*)(&pCTR->ctr[0]), 4);
|
|
*((uint32*)(&pCTR->ctr[0])) += offset_blocks;
|
|
SwapEndian((uint32*)(&pCTR->ctr[0]), 4);
|
|
|
|
ctr_setiv(pCTR->ctr, pCTR->ctrlen, pCTR);
|
|
}
|
|
|
|
// Seek into the last block to initialize the padding
|
|
unsigned int bytesConsumed = 0;
|
|
while (bytesConsumed < offset_remaining)
|
|
{
|
|
const static unsigned int bufSize = 1024;
|
|
unsigned char buffer[bufSize] = {0};
|
|
unsigned int bytesToConsume = min(bufSize, offset_remaining - bytesConsumed);
|
|
ctr_decrypt(buffer, buffer, bytesToConsume, pCTR);
|
|
bytesConsumed += bytesToConsume;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ZipEncrypt::FinishStreamCipher(symmetric_CTR* pCTR)
|
|
{
|
|
ctr_done(pCTR);
|
|
}
|
|
|
|
bool ZipEncrypt::DecryptBufferWithStreamCipher(unsigned char* inBuffer, unsigned char* outBuffer, size_t bufferSize, symmetric_CTR* pCTR)
|
|
{
|
|
int err;
|
|
err = ctr_decrypt(inBuffer, outBuffer, bufferSize, pCTR);
|
|
if (err != CRYPT_OK)
|
|
{
|
|
//printf("ctr_encrypt error: %s\n", error_to_string(errno));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ZipEncrypt::DecryptBufferWithStreamCipher(unsigned char* inBuffer, size_t bufferSize, unsigned char key[16], unsigned char IV[16])
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION
|
|
|
|
symmetric_CTR ctr;
|
|
|
|
if (!StartStreamCipher(key, IV, &ctr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!DecryptBufferWithStreamCipher(inBuffer, inBuffer, bufferSize, &ctr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ctr_done(&ctr);
|
|
|
|
return true;
|
|
}
|
|
|
|
int ZipEncrypt::GetEncryptionKeyIndex(const AZ::IO::ZipDir::FileEntry* pFileEntry)
|
|
{
|
|
return (~(pFileEntry->desc.lCRC32 >> 2)) & 0xF;
|
|
}
|
|
|
|
void ZipEncrypt::GetEncryptionInitialVector(const AZ::IO::ZipDir::FileEntry* pFileEntry, unsigned char IV[16])
|
|
{
|
|
uint32 intIV[4]; //16 byte
|
|
|
|
intIV[0] = pFileEntry->desc.lSizeUncompressed ^ (pFileEntry->desc.lSizeCompressed << 12);
|
|
intIV[1] = (!pFileEntry->desc.lSizeCompressed);
|
|
intIV[2] = pFileEntry->desc.lCRC32 ^ (pFileEntry->desc.lSizeCompressed << 12);
|
|
intIV[3] = !pFileEntry->desc.lSizeUncompressed ^ pFileEntry->desc.lSizeCompressed;
|
|
|
|
memcpy(IV, intIV, sizeof(intIV));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool ZipEncrypt::RSA_VerifyData(void* inBuffer, int sizeIn, unsigned char* signedHash, int signedHashSize, rsa_key& publicKey)
|
|
{
|
|
// verify hash
|
|
|
|
int sha256 = find_hash ("sha256");
|
|
if (sha256 == -1)
|
|
{
|
|
#if !defined(_RELEASE)
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR_DBGBRK, "Hash program for RSA_VerifyData could not be found. LibTomCrypt has failed to start.");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
int hashSize = 32; // 32 bytes for SHA 256
|
|
|
|
unsigned char hash_digest[1024]; // 32 bytes should be enough
|
|
|
|
hash_state md;
|
|
hash_descriptor[sha256].init(&md);
|
|
hash_descriptor[sha256].process(&md, (unsigned char*)inBuffer, sizeIn);
|
|
hash_descriptor[sha256].done(&md, hash_digest); // 32 bytes
|
|
|
|
assert(hash_descriptor[sha256].hashsize == hashSize);
|
|
|
|
int prng_idx = find_prng("yarrow");
|
|
assert(prng_idx != -1);
|
|
|
|
// Verify generated hash with RSA public key
|
|
int statOut = 0;
|
|
int res = rsa_verify_hash(signedHash, signedHashSize, hash_digest, hashSize, sha256, 0, &statOut, &publicKey);
|
|
if (res != CRYPT_OK || statOut != 1)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ZipEncrypt::RSA_VerifyData(const unsigned char** inBuffers, unsigned int* sizesIn, const int numBuffers, unsigned char* signedHash, int signedHashSize, rsa_key& publicKey)
|
|
{
|
|
// verify hash from multiple buffers
|
|
|
|
int sha256 = find_hash ("sha256");
|
|
if (sha256 == -1)
|
|
{
|
|
#if !defined(_RELEASE)
|
|
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR_DBGBRK, "Hash program for RSA_VerifyData could not be found. LibTomCrypt has failed to start.");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
int hashSize = 32; // 32 bytes for SHA 256
|
|
|
|
unsigned char hash_digest[1024]; // 32 bytes should be enough
|
|
|
|
hash_state md;
|
|
hash_descriptor[sha256].init(&md);
|
|
for (int i = 0; i < numBuffers; i++)
|
|
{
|
|
hash_descriptor[sha256].process(&md, inBuffers[i], sizesIn[i]);
|
|
}
|
|
hash_descriptor[sha256].done(&md, hash_digest); // 32 bytes
|
|
|
|
assert(hash_descriptor[sha256].hashsize == hashSize);
|
|
|
|
int prng_idx = find_prng("yarrow");
|
|
assert(prng_idx != -1);
|
|
|
|
// Verify generated hash with RSA public key
|
|
int statOut = 0;
|
|
int res = rsa_verify_hash(signedHash, signedHashSize, hash_digest, hashSize, sha256, 0, &statOut, &publicKey);
|
|
if (res != CRYPT_OK || statOut != 1)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int ZipEncrypt::custom_rsa_encrypt_key_ex(const unsigned char* in, unsigned long inlen,
|
|
unsigned char* out, unsigned long* outlen,
|
|
const unsigned char* lparam, unsigned long lparamlen,
|
|
prng_state* prng, int prng_idx, int hash_idx, int padding, rsa_key* key)
|
|
{
|
|
unsigned long modulus_bitlen, modulus_bytelen, x;
|
|
int err;
|
|
|
|
LTC_ARGCHK(in != NULL);
|
|
LTC_ARGCHK(out != NULL);
|
|
LTC_ARGCHK(outlen != NULL);
|
|
LTC_ARGCHK(key != NULL);
|
|
|
|
/* valid padding? */
|
|
if ((padding != LTC_LTC_PKCS_1_V1_5) &&
|
|
(padding != LTC_LTC_PKCS_1_OAEP))
|
|
{
|
|
return CRYPT_PK_INVALID_PADDING;
|
|
}
|
|
|
|
/* valid prng? */
|
|
if ((err = prng_is_valid(prng_idx)) != CRYPT_OK)
|
|
{
|
|
return err;
|
|
}
|
|
|
|
if (padding == LTC_LTC_PKCS_1_OAEP)
|
|
{
|
|
/* valid hash? */
|
|
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK)
|
|
{
|
|
return err;
|
|
}
|
|
}
|
|
|
|
/* get modulus len in bits */
|
|
modulus_bitlen = mp_count_bits((key->N));
|
|
|
|
/* outlen must be at least the size of the modulus */
|
|
modulus_bytelen = mp_unsigned_bin_size((key->N));
|
|
if (modulus_bytelen > *outlen)
|
|
{
|
|
*outlen = modulus_bytelen;
|
|
return CRYPT_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
if (padding == LTC_LTC_PKCS_1_OAEP)
|
|
{
|
|
/* OAEP pad the key */
|
|
x = *outlen;
|
|
if ((err = pkcs_1_oaep_encode(in, inlen, lparam,
|
|
lparamlen, modulus_bitlen, prng, prng_idx, hash_idx,
|
|
out, &x)) != CRYPT_OK)
|
|
{
|
|
return err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* LTC_PKCS #1 v1.5 pad the key */
|
|
x = *outlen;
|
|
if ((err = pkcs_1_v1_5_encode(in, inlen, LTC_LTC_PKCS_1_EME,
|
|
modulus_bitlen, prng, prng_idx,
|
|
out, &x)) != CRYPT_OK)
|
|
{
|
|
return err;
|
|
}
|
|
}
|
|
|
|
/* rsa exptmod the OAEP or LTC_PKCS #1 v1.5 pad */
|
|
return ltc_mp.rsa_me(out, x, out, outlen, PK_PRIVATE, key);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int ZipEncrypt::custom_rsa_decrypt_key_ex(const unsigned char* in, unsigned long inlen,
|
|
unsigned char* out, unsigned long* outlen,
|
|
const unsigned char* lparam, unsigned long lparamlen,
|
|
int hash_idx, int padding,
|
|
int* stat, rsa_key* key)
|
|
{
|
|
unsigned long modulus_bitlen, modulus_bytelen, x;
|
|
int err;
|
|
unsigned char* tmp;
|
|
|
|
LTC_ARGCHK(out != NULL);
|
|
LTC_ARGCHK(outlen != NULL);
|
|
LTC_ARGCHK(key != NULL);
|
|
LTC_ARGCHK(stat != NULL);
|
|
|
|
/* default to invalid */
|
|
*stat = 0;
|
|
|
|
/* valid padding? */
|
|
|
|
if ((padding != LTC_LTC_PKCS_1_V1_5) &&
|
|
(padding != LTC_LTC_PKCS_1_OAEP))
|
|
{
|
|
return CRYPT_PK_INVALID_PADDING;
|
|
}
|
|
|
|
if (padding == LTC_LTC_PKCS_1_OAEP)
|
|
{
|
|
/* valid hash ? */
|
|
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK)
|
|
{
|
|
return err;
|
|
}
|
|
}
|
|
|
|
/* get modulus len in bits */
|
|
modulus_bitlen = mp_count_bits((key->N));
|
|
|
|
/* outlen must be at least the size of the modulus */
|
|
modulus_bytelen = mp_unsigned_bin_size((key->N));
|
|
if (modulus_bytelen != inlen)
|
|
{
|
|
return CRYPT_INVALID_PACKET;
|
|
}
|
|
|
|
/* allocate ram */
|
|
tmp = (unsigned char*)XMALLOC(inlen);
|
|
if (tmp == NULL)
|
|
{
|
|
return CRYPT_MEM;
|
|
}
|
|
|
|
/* rsa decode the packet */
|
|
x = inlen;
|
|
if ((err = ltc_mp.rsa_me(in, inlen, tmp, &x, PK_PUBLIC, key)) != CRYPT_OK)
|
|
{
|
|
XFREE(tmp);
|
|
return err;
|
|
}
|
|
|
|
if (padding == LTC_LTC_PKCS_1_OAEP)
|
|
{
|
|
/* now OAEP decode the packet */
|
|
err = pkcs_1_oaep_decode(tmp, x, lparam, lparamlen, modulus_bitlen, hash_idx,
|
|
out, outlen, stat);
|
|
}
|
|
else
|
|
{
|
|
/* now LTC_PKCS #1 v1.5 depad the packet */
|
|
err = pkcs_1_v1_5_decode(tmp, x, LTC_LTC_PKCS_1_EME, modulus_bitlen, out, outlen, stat);
|
|
}
|
|
|
|
XFREE(tmp);
|
|
return err;
|
|
}
|
|
|
|
#endif //INCLUDE_LIBTOMCRYPT
|
|
//////////////////////////////////////////////////////////////////////////
|