1 // Crypto/WzAes.h
2 /*
3 This code implements Brian Gladman's scheme
4 specified in "A Password Based File Encryption Utility":
5   - AES encryption (128,192,256-bit) in Counter (CTR) mode.
6   - HMAC-SHA1 authentication for encrypted data (10 bytes)
7   - Keys are derived by PPKDF2(RFC2898)-HMAC-SHA1 from ASCII password and
8     Salt (saltSize = aesKeySize / 2).
9   - 2 bytes contain Password Verifier's Code
10 */
11 
12 #ifndef __CRYPTO_WZ_AES_H
13 #define __CRYPTO_WZ_AES_H
14 
15 #include "../../../C/Aes.h"
16 
17 #include "../../Common/MyBuffer.h"
18 #include "../../Common/MyCom.h"
19 
20 #include "../ICoder.h"
21 #include "../IPassword.h"
22 
23 #include "HmacSha1.h"
24 
25 namespace NCrypto {
26 namespace NWzAes {
27 
28 /* ICompressFilter::Init() does nothing for this filter.
29 
30   Call to init:
31     Encoder:
32       CryptoSetPassword();
33       WriteHeader();
34     Decoder:
35       [CryptoSetPassword();]
36       ReadHeader();
37       [CryptoSetPassword();] Init_and_CheckPassword();
38       [CryptoSetPassword();] Init_and_CheckPassword();
39 */
40 
41 const UInt32 kPasswordSizeMax = 99; // 128;
42 
43 const unsigned kSaltSizeMax = 16;
44 const unsigned kPwdVerifSize = 2;
45 const unsigned kMacSize = 10;
46 
47 enum EKeySizeMode
48 {
49   kKeySizeMode_AES128 = 1,
50   kKeySizeMode_AES192 = 2,
51   kKeySizeMode_AES256 = 3
52 };
53 
54 struct CKeyInfo
55 {
56   EKeySizeMode KeySizeMode;
57   Byte Salt[kSaltSizeMax];
58   Byte PwdVerifComputed[kPwdVerifSize];
59 
60   CByteBuffer Password;
61 
GetKeySizeCKeyInfo62   unsigned GetKeySize()  const { return (8 * KeySizeMode + 8); }
GetSaltSizeCKeyInfo63   unsigned GetSaltSize() const { return (4 * KeySizeMode + 4); }
GetNumSaltWordsCKeyInfo64   unsigned GetNumSaltWords() const { return (KeySizeMode + 1); }
65 
CKeyInfoCKeyInfo66   CKeyInfo(): KeySizeMode(kKeySizeMode_AES256) {}
67 };
68 
69 struct CAesCtr2
70 {
71   unsigned pos;
72   unsigned offset;
73   UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3];
74   CAesCtr2();
75 };
76 
77 void AesCtr2_Init(CAesCtr2 *p);
78 void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size);
79 
80 class CBaseCoder:
81   public ICompressFilter,
82   public ICryptoSetPassword,
83   public CMyUnknownImp
84 {
85 protected:
86   CKeyInfo _key;
87   NSha1::CHmac _hmac;
88   CAesCtr2 _aes;
89 
90   void Init2();
91 public:
92   MY_UNKNOWN_IMP1(ICryptoSetPassword)
93 
94   STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
95 
96   STDMETHOD(Init)();
97 
GetHeaderSize()98   unsigned GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifSize; }
GetAddPackSize()99   unsigned GetAddPackSize() const { return GetHeaderSize() + kMacSize; }
100 
SetKeyMode(unsigned mode)101   bool SetKeyMode(unsigned mode)
102   {
103     if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256)
104       return false;
105     _key.KeySizeMode = (EKeySizeMode)mode;
106     return true;
107   }
108 
~CBaseCoder()109   virtual ~CBaseCoder() {}
110 };
111 
112 class CEncoder:
113   public CBaseCoder
114 {
115 public:
116   STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
117   HRESULT WriteHeader(ISequentialOutStream *outStream);
118   HRESULT WriteFooter(ISequentialOutStream *outStream);
119 };
120 
121 class CDecoder:
122   public CBaseCoder
123   // public ICompressSetDecoderProperties2
124 {
125   Byte _pwdVerifFromArchive[kPwdVerifSize];
126 public:
127   // ICompressSetDecoderProperties2
128   // STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
129   STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
130   HRESULT ReadHeader(ISequentialInStream *inStream);
131   bool Init_and_CheckPassword();
132   HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK);
133 };
134 
135 }}
136 
137 #endif
138