解密AES加密文件,导致崩溃的功能

时间:2014-11-14 14:57:24

标签: c++ mfc crash return aes

我正在尝试编写一个C ++程序来加密和解密某些文件。加密工作正常,但是当我解密时,该功能似乎导致程序崩溃。

这是我用于解密的功能:

    CString DecryptFile(CString csSourceFile)
    {

    CString csDecryptedFile = csSourceFile;
    CRijndael aesEncryption;

    int nPos = csDecryptedFile.ReverseFind('.');

    if(nPos == -1)
    {
        //Log("ERROR:: file name not proper");
        return CString("");
    }

    csDecryptedFile = csDecryptedFile.Left(nPos);
    csDecryptedFile += ".wav";

    FILE *fIn = fopen(csSourceFile.GetBuffer(0),"rb");
    FILE *fOut = fopen(csDecryptedFile.GetBuffer(0),"wb");

    if(!fIn || !fOut)
    {
        //Log("ERROR:: failed to Open File for encryption");
        return CString("");
    }

    int nlen = -1;

    aesEncryption.MakeKey(AM_ENC_KEY,AM_NULL_KEY,BLOCK_SIZE,BLOCK_SIZE);

    int nRead = 0;
    while (true) {
        char szBlockIn[EBLOCK_SIZE+1] = {0};
        char szBlockOut[BLOCK_SIZE+1] = {0};
        char szBlockDec[BLOCK_SIZE+1] = {0};

        memset(szBlockIn,0,sizeof(char)*(EBLOCK_SIZE+1));
        memset(szBlockOut,0,sizeof(char)*(BLOCK_SIZE+1));
        memset(szBlockDec,0,sizeof(char)*(BLOCK_SIZE+1));

        int nRead = fread(szBlockIn,sizeof(char),EBLOCK_SIZE, fIn);
        if(nRead <= 0) {
            break;
        }

        nlen = EBLOCK_SIZE;
        Decode(szBlockIn,szBlockOut,nlen);
        aesEncryption.DecryptBlock((char *)szBlockOut,szBlockDec);
        fwrite(szBlockDec,sizeof(char),BLOCK_SIZE,fOut);
    }

    fclose(fIn);
    fclose(fOut);

    RemoveEndTag(csDecryptedFile.GetBuffer(0));
    AfxMessageBox(csDecryptedFile);
    AfxMessageBox(_T("returning"));
    return csDecryptedFile;
}

这是调用函数的代码片段:

CString strTest = DecryptFile(m_DecompressedTempFile);
AfxMessageBox(strTest);

奇怪的是,解密执行得非常好 - 如果我到达文件位置,我可以看到解密文件并访问它。不幸的是,程序必须做更多的事情,程序只是紧随其后。特别奇怪的是,你可以看到我在函数结束前调用AfxMessageBox(_T("returning"));:这会产生一个消息框。但是,当我从运行该函数的代码中调用AfxMessageBox(strTest);时,不会生成任何消息框。

通过调试,似乎问题以某种方式在我用于加密文件的while循环中路由,所以我想知道我是不是要关闭我应该做的东西或什么?不知道该怎么办,所以任何能提供任何帮助的人都会很棒!?!

提前致谢。

我忘了提到这已经存在多年了 - 最近唯一的变化是我们现在正在编译Windows 7上的代码,而之前是Windows XP。这会对函数中的任何内容产生影响吗?

更新:值得注意的是,如果我删除while循环并只运行一次循环内容,则会出现同样的问题。如果我删除了aesEncryption.DecryptBlock((char *)szBlockOut,szBlockDec);,那么问题就会消失,但显然我需要那条线。所以我认为问题就转移到了这个功能上。虽然这个函数存在于库中,但我将它包含在下面:

//Decrypt exactly one block of ciphertext.
// in         - The ciphertext.
// result     - The plaintext generated from a ciphertext using the session key.
void CRijndael::DecryptBlock(char const* in, char* result)
{
    if(false==m_bKeyInit)
        throw exception(sm_szErrorMsg1);
    if(DEFAULT_BLOCK_SIZE == m_blockSize)
    {
        DefDecryptBlock(in, result);
        return;
    }
    int BC = m_blockSize / 4;
    int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2);
    int s1 = sm_shifts[SC][1][1];
    int s2 = sm_shifts[SC][2][1];
    int s3 = sm_shifts[SC][3][1];
    //Temporary Work Arrays
    int i;
    int tt;
    int* pi = t;
    for(i=0; i<BC; i++)
    {
        *pi = ((unsigned char)*(in++) << 24);
        *pi |= ((unsigned char)*(in++) << 16);
        *pi |= ((unsigned char)*(in++) << 8);
        (*(pi++) |= (unsigned char)*(in++)) ^= m_Kd[0][i];
    }
    //Apply Round Transforms
    for(int r=1; r<m_iROUNDS; r++)
    {
        for(i=0; i<BC; i++)
            a[i] = (sm_T5[(t[i] >> 24) & 0xFF] ^
                sm_T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
                sm_T7[(t[(i + s2) % BC] >>  8) & 0xFF] ^
                sm_T8[ t[(i + s3) % BC] & 0xFF]) ^ m_Kd[r][i];
        memcpy(t, a, 4*BC);
    }
    int j;
    //Last Round is Special
    for(i=0,j=0; i<BC; i++)
    {
        tt = m_Kd[m_iROUNDS][i];
        result[j++] = sm_Si[(t[i] >> 24) & 0xFF] ^ (tt >> 24);
        result[j++] = sm_Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16);
        result[j++] = sm_Si[(t[(i + s2) % BC] >>  8) & 0xFF] ^ (tt >>  8);
        result[j++] = sm_Si[ t[(i + s3) % BC] & 0xFF] ^ tt;
    }
}

1 个答案:

答案 0 :(得分:0)

目前尚不清楚您是否只想要C ++解决方案;如果您对Python解决方案没问题,请尝试使用PyCrypto模块。这是我用来压缩当前目录的内容,除了一些忽略模式,并加密./bin下的.zip(大部分是从SO上其他地方复制的代码):

import sys
import os
import zipfile
import getpass
from contextlib import contextmanager
from hashlib import md5
from Crypto.Cipher import AES
from Crypto import Random

def derive_key_and_iv(password, salt, key_length, iv_length):
    d = d_i = ''
    while len(d) < key_length + iv_length:
        d_i = md5(d_i + password + salt).digest()
        d += d_i
    return d[:key_length], d[key_length:key_length+iv_length]

def encrypt(in_file, out_file, password, key_length=32):
    bs = AES.block_size
    salt = Random.new().read(bs - len('Salted__'))
    key, iv = derive_key_and_iv(password, salt, key_length, bs)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    out_file.write('Salted__' + salt)
    finished = False
    while not finished:
        chunk = in_file.read(1024 * bs)
        if len(chunk) == 0 or len(chunk) % bs != 0:
            padding_length = (bs - len(chunk) % bs) or bs
            chunk += padding_length * chr(padding_length)
            finished = True
        out_file.write(cipher.encrypt(chunk))

def decrypt(in_file, out_file, password, key_length=32):
    bs = AES.block_size
    salt = in_file.read(bs)[len('Salted__'):]
    key, iv = derive_key_and_iv(password, salt, key_length, bs)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    next_chunk = ''
    finished = False
    while not finished:
        chunk, next_chunk = next_chunk, cipher.decrypt(in_file.read(1024 * bs))
        if len(next_chunk) == 0:
            padding_length = ord(chunk[-1])
            chunk = chunk[:-padding_length]
            finished = True
        out_file.write(chunk)

def query_yes_no(question, default="yes", quiet=False):
    """Ask a yes/no question via raw_input() and return their answer.

    "question" is a string that is presented to the user.
    "default" is the presumed answer if the user just hits <Enter>.
        It must be "yes" (the default), "no" or None (meaning
        an answer is required of the user).

    The "answer" return value is True for "yes" or False for "no".
    """
    valid = {"yes": True, "y": True, "ye": True,
             "no": False, "n": False}
    if default is None:
        prompt = " [y/n] "
    elif default == "yes":
        prompt = " [Y/n] "
    elif default == "no":
        prompt = " [y/N] "
    else:
        raise ValueError("invalid default answer: '%s'" % default)
    while True:
        if not quiet:
          sys.stdout.write(question + prompt)
        if quiet and default is not None:
          choice=default
        else:
          choice = raw_input().lower()
        if default is not None and choice == '':
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            sys.stdout.write("Please respond with 'yes' or 'no' "
                             "(or 'y' or 'n')\n")

dircurr=os.path.abspath('.').replace('\\','/')
dirwithenc=dircurr+'/bin'
if os.path.isfile(dirwithenc+'/bak.enc'):
  if query_yes_no("\nDo you want to decrypt '"+dirwithenc+"/bak.enc'?",'no'):
    password=getpass.getpass('\nDecryption password: ')
    with open(dirwithenc+'/bak.enc', 'rb') as in_file, open(dircurr+'/bak.zip', 'wb') as out_file:
      decrypt(in_file,out_file,password)
    print("\nFile '"+dircurr+"/bak.enc' decrypted to '"+dircurr+"/bak.zip'")
    raw_input("""
***DONE***

Press Enter...""")
    exit(0)
  else:
    print("\nAnswered 'no'")
print("\nEncrypting files will overwrite any preexisting file '"+dirwithenc+"/bak.enc'")
password=getpass.getpass('\nSet an encryption password (will not be saved): ')
print('\nZipping files, excepting certain ignore patterns...')
zf = zipfile.ZipFile(dircurr+'/bak.zip', 'w')
for dirname, subdirs, files in os.walk(os.path.abspath('.')):
  #Do not archive system files beginning with period
  for filename in files:
    if filename[:1]=='.':
      files.remove(filename)
  #Do not archive the binaries directory, it should just be delivered as is
  if 'bin' in subdirs:
    subdirs.remove('bin')
  #Do not archive any previous archives, or you will just make a giant snowball
  if 'bak.zip' in files:
    files.remove('bak.zip')
  if 'bak.enc' in files:
    files.remove('bak.enc')
  zf.write(dirname)
  for filename in files:
    zf.write(os.path.join(dirname, filename))
#If there was a folder 'dat' under the binaries folder, then archive it too,
#so that you have everything you need to rebuild the project
print("Including files under 'bin/dat'")
if os.path.isdir(dircurr+'/bin/dat'):
  for dirname, subdirs, files in os.walk(dircurr+'/bin/dat'):
    if 'bin' in subdirs:
      subdirs.remove('bin')
    zf.write(dirname)
    for filename in files:
      zf.write(os.path.join(dirname, filename))
#If there were any files '*.ico' under the binaries folder, then archive them too,
#so that you have everything you need to rebuild the project
print("Including .ico files under 'bin'")
for dirname, subdirs, files in os.walk(dircurr+'/bin'):
  for filename in files:
    if filename[-4:]=='.ico':
      zf.write(os.path.join(dirname, filename))
zf.close()
print("\nZipped to '"+dircurr+"/bak.zip'")
print("\nEncrypting zipped file and removing unencrypted zipped file...")
with open(dircurr+'/bak.zip', 'rb') as in_file, open(dirwithenc+'/bak.enc', 'wb') as out_file:
  encrypt(in_file, out_file, password)
os.remove(dircurr+'/bak.zip')
print("\nEncrypted to '"+dirwithenc+"/bak.enc'")
raw_input("""
***DONE***

Press Enter...""")
exit(0)