annotate src/win32/7zip/7z/CPP/7zip/Crypto/WzAes.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
rev   line source
rlm@1 1 // Crypto/WzAes.cpp
rlm@1 2 /*
rlm@1 3 This code implements Brian Gladman's scheme
rlm@1 4 specified in password Based File Encryption Utility.
rlm@1 5
rlm@1 6 Note: you must include MyAes.cpp to project to initialize AES tables
rlm@1 7 */
rlm@1 8
rlm@1 9 #include "StdAfx.h"
rlm@1 10
rlm@1 11 #include "../Common/StreamObjects.h"
rlm@1 12 #include "../Common/StreamUtils.h"
rlm@1 13
rlm@1 14 #include "Pbkdf2HmacSha1.h"
rlm@1 15 #include "RandGen.h"
rlm@1 16 #include "WzAes.h"
rlm@1 17
rlm@1 18 // define it if you don't want to use speed-optimized version of Pbkdf2HmacSha1
rlm@1 19 // #define _NO_WZAES_OPTIMIZATIONS
rlm@1 20
rlm@1 21 namespace NCrypto {
rlm@1 22 namespace NWzAes {
rlm@1 23
rlm@1 24 const unsigned int kAesKeySizeMax = 32;
rlm@1 25
rlm@1 26 static const UInt32 kNumKeyGenIterations = 1000;
rlm@1 27
rlm@1 28 STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
rlm@1 29 {
rlm@1 30 if(size > kPasswordSizeMax)
rlm@1 31 return E_INVALIDARG;
rlm@1 32 _key.Password.SetCapacity(size);
rlm@1 33 memcpy(_key.Password, data, size);
rlm@1 34 return S_OK;
rlm@1 35 }
rlm@1 36
rlm@1 37 #define SetUi32(p, d) { UInt32 x = (d); (p)[0] = (Byte)x; (p)[1] = (Byte)(x >> 8); \
rlm@1 38 (p)[2] = (Byte)(x >> 16); (p)[3] = (Byte)(x >> 24); }
rlm@1 39
rlm@1 40 void CBaseCoder::EncryptData(Byte *data, UInt32 size)
rlm@1 41 {
rlm@1 42 unsigned int pos = _blockPos;
rlm@1 43 for (; size > 0; size--)
rlm@1 44 {
rlm@1 45 if (pos == AES_BLOCK_SIZE)
rlm@1 46 {
rlm@1 47 if (++_counter[0] == 0)
rlm@1 48 _counter[1]++;
rlm@1 49 UInt32 temp[4];
rlm@1 50 Aes_Encode32(&Aes, temp, _counter);
rlm@1 51 SetUi32(_buffer, temp[0]);
rlm@1 52 SetUi32(_buffer + 4, temp[1]);
rlm@1 53 SetUi32(_buffer + 8, temp[2]);
rlm@1 54 SetUi32(_buffer + 12, temp[3]);
rlm@1 55 pos = 0;
rlm@1 56 }
rlm@1 57 *data++ ^= _buffer[pos++];
rlm@1 58 }
rlm@1 59 _blockPos = pos;
rlm@1 60 }
rlm@1 61
rlm@1 62 #ifndef _NO_WZAES_OPTIMIZATIONS
rlm@1 63
rlm@1 64 static void BytesToBeUInt32s(const Byte *src, UInt32 *dest, int destSize)
rlm@1 65 {
rlm@1 66 for (int i = 0 ; i < destSize; i++)
rlm@1 67 dest[i] =
rlm@1 68 ((UInt32)(src[i * 4 + 0]) << 24) |
rlm@1 69 ((UInt32)(src[i * 4 + 1]) << 16) |
rlm@1 70 ((UInt32)(src[i * 4 + 2]) << 8) |
rlm@1 71 ((UInt32)(src[i * 4 + 3]));
rlm@1 72 }
rlm@1 73
rlm@1 74 #endif
rlm@1 75
rlm@1 76 STDMETHODIMP CBaseCoder::Init()
rlm@1 77 {
rlm@1 78 UInt32 keySize = _key.GetKeySize();
rlm@1 79 UInt32 keysTotalSize = 2 * keySize + kPwdVerifCodeSize;
rlm@1 80 Byte buf[2 * kAesKeySizeMax + kPwdVerifCodeSize];
rlm@1 81
rlm@1 82 // for (int ii = 0; ii < 1000; ii++)
rlm@1 83 {
rlm@1 84 #ifdef _NO_WZAES_OPTIMIZATIONS
rlm@1 85
rlm@1 86 NSha1::Pbkdf2Hmac(
rlm@1 87 _key.Password, _key.Password.GetCapacity(),
rlm@1 88 _key.Salt, _key.GetSaltSize(),
rlm@1 89 kNumKeyGenIterations,
rlm@1 90 buf, keysTotalSize);
rlm@1 91
rlm@1 92 #else
rlm@1 93
rlm@1 94 UInt32 buf32[(2 * kAesKeySizeMax + kPwdVerifCodeSize + 3) / 4];
rlm@1 95 UInt32 key32SizeTotal = (keysTotalSize + 3) / 4;
rlm@1 96 UInt32 salt[kSaltSizeMax * 4];
rlm@1 97 UInt32 saltSizeInWords = _key.GetSaltSize() / 4;
rlm@1 98 BytesToBeUInt32s(_key.Salt, salt, saltSizeInWords);
rlm@1 99 NSha1::Pbkdf2Hmac32(
rlm@1 100 _key.Password, _key.Password.GetCapacity(),
rlm@1 101 salt, saltSizeInWords,
rlm@1 102 kNumKeyGenIterations,
rlm@1 103 buf32, key32SizeTotal);
rlm@1 104 for (UInt32 j = 0; j < keysTotalSize; j++)
rlm@1 105 buf[j] = (Byte)(buf32[j / 4] >> (24 - 8 * (j & 3)));
rlm@1 106
rlm@1 107 #endif
rlm@1 108 }
rlm@1 109
rlm@1 110 _hmac.SetKey(buf + keySize, keySize);
rlm@1 111 memcpy(_key.PwdVerifComputed, buf + 2 * keySize, kPwdVerifCodeSize);
rlm@1 112
rlm@1 113 _blockPos = AES_BLOCK_SIZE;
rlm@1 114 for (int i = 0; i < 4; i++)
rlm@1 115 _counter[i] = 0;
rlm@1 116
rlm@1 117 Aes_SetKeyEncode(&Aes, buf, keySize);
rlm@1 118 return S_OK;
rlm@1 119 }
rlm@1 120
rlm@1 121 /*
rlm@1 122 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
rlm@1 123 {
rlm@1 124 Byte keySizeMode = 3;
rlm@1 125 return outStream->Write(&keySizeMode, 1, NULL);
rlm@1 126 }
rlm@1 127 */
rlm@1 128
rlm@1 129 HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
rlm@1 130 {
rlm@1 131 UInt32 saltSize = _key.GetSaltSize();
rlm@1 132 g_RandomGenerator.Generate(_key.Salt, saltSize);
rlm@1 133 Init();
rlm@1 134 RINOK(WriteStream(outStream, _key.Salt, saltSize));
rlm@1 135 return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifCodeSize);
rlm@1 136 }
rlm@1 137
rlm@1 138 HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
rlm@1 139 {
rlm@1 140 Byte mac[kMacSize];
rlm@1 141 _hmac.Final(mac, kMacSize);
rlm@1 142 return WriteStream(outStream, mac, kMacSize);
rlm@1 143 }
rlm@1 144
rlm@1 145 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
rlm@1 146 {
rlm@1 147 if (size != 1)
rlm@1 148 return E_INVALIDARG;
rlm@1 149 _key.Init();
rlm@1 150 Byte keySizeMode = data[0];
rlm@1 151 if (keySizeMode < 1 || keySizeMode > 3)
rlm@1 152 return E_INVALIDARG;
rlm@1 153 _key.KeySizeMode = keySizeMode;
rlm@1 154 return S_OK;
rlm@1 155 }
rlm@1 156
rlm@1 157 HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
rlm@1 158 {
rlm@1 159 UInt32 saltSize = _key.GetSaltSize();
rlm@1 160 UInt32 extraSize = saltSize + kPwdVerifCodeSize;
rlm@1 161 Byte temp[kSaltSizeMax + kPwdVerifCodeSize];
rlm@1 162 RINOK(ReadStream_FAIL(inStream, temp, extraSize));
rlm@1 163 UInt32 i;
rlm@1 164 for (i = 0; i < saltSize; i++)
rlm@1 165 _key.Salt[i] = temp[i];
rlm@1 166 for (i = 0; i < kPwdVerifCodeSize; i++)
rlm@1 167 _pwdVerifFromArchive[i] = temp[saltSize + i];
rlm@1 168 return S_OK;
rlm@1 169 }
rlm@1 170
rlm@1 171 static bool CompareArrays(const Byte *p1, const Byte *p2, UInt32 size)
rlm@1 172 {
rlm@1 173 for (UInt32 i = 0; i < size; i++)
rlm@1 174 if (p1[i] != p2[i])
rlm@1 175 return false;
rlm@1 176 return true;
rlm@1 177 }
rlm@1 178
rlm@1 179 bool CDecoder::CheckPasswordVerifyCode()
rlm@1 180 {
rlm@1 181 return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifCodeSize);
rlm@1 182 }
rlm@1 183
rlm@1 184 HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
rlm@1 185 {
rlm@1 186 isOK = false;
rlm@1 187 Byte mac1[kMacSize];
rlm@1 188 RINOK(ReadStream_FAIL(inStream, mac1, kMacSize));
rlm@1 189 Byte mac2[kMacSize];
rlm@1 190 _hmac.Final(mac2, kMacSize);
rlm@1 191 isOK = CompareArrays(mac1, mac2, kMacSize);
rlm@1 192 return S_OK;
rlm@1 193 }
rlm@1 194
rlm@1 195 STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
rlm@1 196 {
rlm@1 197 EncryptData(data, size);
rlm@1 198 _hmac.Update(data, size);
rlm@1 199 return size;
rlm@1 200 }
rlm@1 201
rlm@1 202 STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
rlm@1 203 {
rlm@1 204 _hmac.Update(data, size);
rlm@1 205 EncryptData(data, size);
rlm@1 206 return size;
rlm@1 207 }
rlm@1 208
rlm@1 209 }}