Rev 26 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 26 | Rev 27 | ||
---|---|---|---|
Line 105... | Line 105... | ||
105 | end; |
105 | end; |
106 | 106 | ||
107 | type |
107 | type |
108 | TDcFormatVersion = (fvUnknown, fvDc40, fvDc41Beta, fvDc41FinalCancelled, fvDc50Wip); |
108 | TDcFormatVersion = (fvUnknown, fvDc40, fvDc41Beta, fvDc41FinalCancelled, fvDc50Wip); |
109 | 109 | ||
- | 110 | TKdfVersion = (kvUnknown, kvKdf1, kvKdf2, kvKdf3, kvKdfx, kvPbkdf2); |
|
- | 111 | ||
- | 112 | TDC4FileInfo = record |
|
- | 113 | Dc4FormatVersion: TDcFormatVersion; |
|
- | 114 | IsZLibCompressed: boolean; |
|
- | 115 | IsCompressedFolder: boolean; |
|
- | 116 | OrigFileName: string; |
|
- | 117 | KDF: TKdfVersion; |
|
- | 118 | KDF_Iterations: Integer; |
|
- | 119 | IVSize: integer; |
|
- | 120 | SeedSize: integer; |
|
- | 121 | HashClass: TDECHashClass; |
|
- | 122 | CipherClass: TDECCipherClass; |
|
- | 123 | CipherMode: TCipherMode; |
|
- | 124 | FillMode: TBlockFillMode; |
|
- | 125 | end; |
|
- | 126 | ||
110 | const |
127 | const |
- | 128 | DC4_SUBFORMAT_VERSION: array[Low(TDcFormatVersion)..High(TDcFormatVersion)] of string = ( |
|
- | 129 | 'Unknown', |
|
- | 130 | '(De)Coder 4.0', |
|
- | 131 | '(De)Coder 4.1 Beta', |
|
- | 132 | '(De)Coder 4.1 Final (Cancelled)', |
|
- | 133 | '(De)Coder 5.0 WIP' |
|
- | 134 | ); |
|
- | 135 | ||
- | 136 | INTEGRITY_CHECK_INFO: array[Low(TDcFormatVersion)..High(TDcFormatVersion)] of string = ( |
|
- | 137 | 'Unknown', // CalcMac for Hagen Reddmann Example |
|
- | 138 | 'Hash of source data', |
|
- | 139 | 'Nested Hash of source data with password', |
|
- | 140 | 'Nested Hash of source data with password', |
|
- | 141 | 'Encrypt-then-HMAC' |
|
- | 142 | ); |
|
- | 143 | ||
- | 144 | KDF_VERSION_NAMES: array[Low(TKdfVersion)..High(TKdfVersion)] of string = ( |
|
- | 145 | 'Unknown', 'KDF1', 'KDF2', 'KDF3', 'KDFx', 'PBKDF2' |
|
- | 146 | ); |
|
- | 147 | ||
- | 148 | CIPHER_MODE_NAMES: array[Low(TCipherMode)..High(TCipherMode)] of string = ( |
|
- | 149 | 'CTSx = double CBC, with CFS8 padding of truncated final block', |
|
- | 150 | 'CBCx = Cipher Block Chaining, with CFB8 padding of truncated final block', |
|
- | 151 | 'CFB8 = 8bit Cipher Feedback mode', |
|
- | 152 | 'CFBx = CFB on Blocksize of Cipher', |
|
- | 153 | 'OFB8 = 8bit Output Feedback mode', |
|
- | 154 | 'OFBx = OFB on Blocksize bytes', |
|
- | 155 | 'CFS8 = 8Bit CFS, double CFB', |
|
- | 156 | 'CFSx = CFS on Blocksize bytes', |
|
- | 157 | 'ECBx = Electronic Code Book', |
|
- | 158 | 'GCM = Galois Counter Mode' |
|
- | 159 | ); |
|
- | 160 | ||
- | 161 | CIPHER_FILLMODE_NAMES: array[Low(TBlockFillMode)..High(TBlockFillMode)] of string = ( |
|
- | 162 | 'Bytes' |
|
- | 163 | ); |
|
- | 164 | ||
111 | DC4_ID_BASES: array[0..4] of Int64 = ( |
165 | DC4_ID_BASES: array[Low(TDcFormatVersion)..High(TDcFormatVersion)] of Int64 = ( |
112 | $84485225, // Hagen Reddmann Example (no .dc4 files) |
166 | $84485225, // Hagen Reddmann Example (no .dc4 files) |
113 | $59178954, // (De)Coder 4.0 (identities not used) |
167 | $59178954, // (De)Coder 4.0 (identities not used) |
114 | $84671842, // (De)Coder 4.1 beta |
168 | $84671842, // (De)Coder 4.1 beta |
115 | $19387612, // (De)Coder 4.1 final/cancelled |
169 | $19387612, // (De)Coder 4.1 final/cancelled |
116 | $1259d82a // (De)Coder 5.0 WIP |
170 | $1259d82a // (De)Coder 5.0 WIP |
Line 174... | Line 228... | ||
174 | finally |
228 | finally |
175 | FreeAndNil(CompressInputStream); |
229 | FreeAndNil(CompressInputStream); |
176 | end; |
230 | end; |
177 | end; |
231 | end; |
178 | 232 | ||
179 | type |
- | |
180 | TKdfVersion = (kvUnknown, kvKdf1, kvKdf2, kvKdf3, kvKdfx, kvPbkdf2); |
- | |
181 | - | ||
182 | TDC4FileInfo = record |
- | |
183 | Dc4FormatVersion: TDcFormatVersion; |
- | |
184 | IsZLibCompressed: boolean; |
- | |
185 | IsCompressedFolder: boolean; |
- | |
186 | OrigFileName: string; |
- | |
187 | KDF: TKdfVersion; |
- | |
188 | KDF_Iterations: Integer; |
- | |
189 | IVSize: integer; |
- | |
190 | SeedSize: integer; |
- | |
191 | HashClass: TDECHashClass; |
- | |
192 | CipherClass: TDECCipherClass; |
- | |
193 | CipherMode: TCipherMode; |
- | |
194 | FillMode: TBlockFillMode; |
- | |
195 | end; |
- | |
196 | - | ||
197 | function DeCoder4X_DecodeFile(const AFileName, AOutput: String; const APassword: RawByteString; const OnlyReadFileInfo: boolean=false): TDC4FileInfo; |
233 | function DeCoder4X_DecodeFile(const AFileName, AOutput: String; const APassword: RawByteString; const OnlyReadFileInfo: boolean=false): TDC4FileInfo; |
198 | var |
234 | var |
199 | Source: TStream; |
235 | Source: TStream; |
200 | 236 | ||
201 | procedure Read(var Value; Size: Integer); |
237 | procedure Read(var Value; Size: Integer); |
Line 366... | Line 402... | ||
366 | else |
402 | else |
367 | Assert(False); |
403 | Assert(False); |
368 | 404 | ||
369 | // 4. IdBase (only version 2+) |
405 | // 4. IdBase (only version 2+) |
370 | if V = fvDc40 then |
406 | if V = fvDc40 then |
371 | idBase := DC4_ID_BASES[Ord(V)] |
407 | idBase := DC4_ID_BASES[V] |
372 | else |
408 | else |
373 | idBase := ReadLong; |
409 | idBase := ReadLong; |
374 | 410 | ||
375 | // 5. Cipher identity (only version 2+) |
411 | // 5. Cipher identity (only version 2+) |
376 | if V = fvDc40 then |
412 | if V = fvDc40 then |
Line 722... | Line 758... | ||
722 | OrigName := UTF8Encode(ExtractFileName(AFileName)); |
758 | OrigName := UTF8Encode(ExtractFileName(AFileName)); |
723 | WriteByte(Length(OrigName)); |
759 | WriteByte(Length(OrigName)); |
724 | WriteRaw(OrigName); |
760 | WriteRaw(OrigName); |
725 | 761 | ||
726 | // 4. IdBase (only version 2+) |
762 | // 4. IdBase (only version 2+) |
727 | idBase := DC4_ID_BASES[Ord(fvDc50Wip)]; |
763 | idBase := DC4_ID_BASES[fvDc50Wip]; |
728 | WriteLong(idBase); |
764 | WriteLong(idBase); |
729 | 765 | ||
730 | // 5. Cipher identity (only version 2+) |
766 | // 5. Cipher identity (only version 2+) |
731 | CipherClass := TCipher_AES; |
767 | CipherClass := TCipher_AES; |
732 | WriteLong(DEC51_Identity(idBase, CipherClass.ClassName)); |
768 | WriteLong(DEC51_Identity(idBase, CipherClass.ClassName)); |
Line 745... | Line 781... | ||
745 | WriteByte(16); |
781 | WriteByte(16); |
746 | IV := RandomBytes(16); |
782 | IV := RandomBytes(16); |
747 | WriteRaw(Convert(IV)); |
783 | WriteRaw(Convert(IV)); |
748 | 784 | ||
749 | // 7.6 Cipher block filling mode (only version 4+) |
785 | // 7.6 Cipher block filling mode (only version 4+) |
- | 786 | Cipher.FillMode := TBlockFillMode.fmByte; |
|
750 | WriteByte(Ord(Cipher.FillMode)); |
787 | WriteByte(Ord(Cipher.FillMode)); |
751 | 788 | ||
752 | // 7.7 Last-Block-Filler (only version 4+) |
789 | // 7.7 Last-Block-Filler (only version 4+) |
753 | Filler := $FF; |
790 | Filler := $FF; |
754 | WriteByte(Filler); |
791 | WriteByte(Filler); |
Line 805... | Line 842... | ||
805 | SecureDeleteFile(ATempFileName); |
842 | SecureDeleteFile(ATempFileName); |
806 | end; |
843 | end; |
807 | end; |
844 | end; |
808 | end; |
845 | end; |
809 | 846 | ||
- | 847 | function YesNo(b: boolean): string; |
|
- | 848 | begin |
|
- | 849 | if b then exit('Yes') else exit('No'); |
|
810 | 850 | end; |
|
811 | 851 | ||
812 | procedure TFormMain.Button1Click(Sender: TObject); |
852 | procedure TFormMain.Button1Click(Sender: TObject); |
813 | var |
853 | var |
814 | fi: TDC4FileInfo; |
854 | fi: TDC4FileInfo; |
815 | begin |
855 | begin |
Line 830... | Line 870... | ||
830 | ShowMessage('ok'); |
870 | ShowMessage('ok'); |
831 | 871 | ||
832 | fi := DeCoder4X_DecodeFile('schloss.dc5', '', '', true); |
872 | fi := DeCoder4X_DecodeFile('schloss.dc5', '', '', true); |
833 | ShowMessage('ok'); |
873 | ShowMessage('ok'); |
834 | 874 | ||
- | 875 | Memo1.Lines.Clear; |
|
- | 876 | ||
- | 877 | Memo1.Lines.Add('File Format: (De)Coder 4.x/5.x Encrypted File'); |
|
- | 878 | Memo1.Lines.Add('Sub-Format: ' + IntToStr(Ord(fi.Dc4FormatVersion)) + ' = ' + DC4_SUBFORMAT_VERSION[fi.Dc4FormatVersion]); |
|
- | 879 | Memo1.Lines.Add('Is compressed folder: ' + YesNo(fi.IsCompressedFolder)); |
|
- | 880 | Memo1.Lines.Add('Data additionally ZLib-compressed: ' + YesNo(fi.IsZLibCompressed)); |
|
- | 881 | Memo1.Lines.Add('Original filename: ' + fi.OrigFileName); |
|
- | 882 | Memo1.Lines.Add('Key Derivation Algorithm: ' + KDF_VERSION_NAMES[fi.KDF]); |
|
- | 883 | if fi.KDF = kvPbkdf2 then |
|
- | 884 | Memo1.Lines.Add('PBKDF Iterations: ' + IntToStr(fi.KDF_Iterations)); |
|
- | 885 | Memo1.Lines.Add('Hashing Algorithm: ' + StringReplace(fi.HashClass.ClassName, 'THash_', '', [])); |
|
- | 886 | Memo1.Lines.Add('Hash Digest Size: ' + IntToStr(fi.HashClass.DigestSize)); |
|
- | 887 | Memo1.Lines.Add('Hash Block Size: ' + IntToStr(fi.HashClass.BlockSize)); |
|
- | 888 | Memo1.Lines.Add('Hash Seed Size: ' + IntToStr(fi.SeedSize)); |
|
- | 889 | Memo1.Lines.Add('Encryption Algorithm: ' + StringReplace(fi.CipherClass.ClassName, 'TCipher_', '', [])); |
|
- | 890 | Memo1.Lines.Add('Cipher Key Size: ' + IntToStr(fi.CipherClass.Context.KeySize)); |
|
- | 891 | Memo1.Lines.Add('Cipher Block Size: ' + IntToStr(fi.CipherClass.Context.BlockSize)); |
|
- | 892 | Memo1.Lines.Add('Cipher Buffer Size: ' + IntToStr(fi.CipherClass.Context.BufferSize)); |
|
- | 893 | Memo1.Lines.Add('Cipher IV Size: ' + IntToStr(fi.IVSize)); |
|
- | 894 | Memo1.Lines.Add('Cipher Mode: ' + CIPHER_MODE_NAMES[fi.CipherMode]); |
|
- | 895 | Memo1.Lines.Add('Cipher Block Filling Mode: ' + CIPHER_FILLMODE_NAMES[fi.FillMode]); |
|
- | 896 | Memo1.Lines.Add('Message Authentication: ' + INTEGRITY_CHECK_INFO[fi.Dc4FormatVersion]); |
|
835 | end; |
897 | end; |
836 | 898 | ||
837 | { TDECHashExtendedAuthentication } |
899 | { TDECHashExtendedAuthentication } |
838 | 900 | ||
839 | class function TDECHashExtendedAuthentication.HMACFile(const Key: TBytes; |
901 | class function TDECHashExtendedAuthentication.HMACFile(const Key: TBytes; |