En m'inspirant sujet WebSocket HTML5 et Delphi pour l'utilisation de CryptAPI pour du MD5, j'ai regardé ce que propose Windows pour AES !

J'ai surtout utilisé les fonctions AES de MySQL, je n'ai jamais eu besoin de le faire réellement !
j'utilise une wcrypt2.pas trouvé sur KODERS, il me manque quelques constantes mal ça se trouve ailleurs !

Une collègue est en ce moment en train de programmer sur son micro-proc 16bits, une version C en s'inspirant de sources trouvés sur le net, elle a un code mais qui ne semble pas donner le bon résultat !

On a des valeurs de test, le Text en Clair, la Clé et le Cypher Text, les résultats ne sont pas les mêmes, j'ai donc baclé en Delphi une petite fonction de test qui retourne le Cypher Text ainsi que la confirmation que l'on peut récupérer la valeur d'origine !

c'est sous XE d'où les AnsiString, oui, je sais mélange AnsiString\PByte, c'est moche, je bosse en C++2007 normalement, ça me fait un petit exercice en Delphi, j'ai perdu le reflexe du @, je me suis habitué au &

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//---------------------------------------------------------------------------
function TTestWebSocketsForm.MakeAES(const Input, Key: AnsiString; out Confirm: AnsiString; AESFinal: boolean): AnsiString;
var
  pbContent: PByte;
  pbResult: PByte;
  pbConfirm: PByte;
  hCryptProvider: HCRYPTPROV;
  KeyBlob: packed record
    Header: BLOBHEADER;
    Size: DWORD;
    Data: array[0..15] of Byte;
  end;
  hKey, hEncryptKey, hDecryptKey: HCRYPTKEY;
  dwKeyCypherMode: DWORD;
  InputLen, ResultLen: DWORD;
const
  PROV_RSA_AES = 24;
  CALG_AES_128 = $0000660e;
begin
  pbContent := Pointer(PAnsiChar(Input));
 
  Result := '';
  // MS_ENH_RSA_AES_PROV
  if CryptAcquireContext(@hCryptProvider, nil, nil, PROV_RSA_AES, CRYPT_VERIFYCONTEXT) then
  begin
    KeyBlob.Header.bType := PLAINTEXTKEYBLOB;
    keyBlob.Header.bVersion := CUR_BLOB_VERSION;
    keyBlob.Header.reserved := 0;
    keyBlob.Header.aiKeyAlg := CALG_AES_128;
    keyBlob.Size := Length(Key) * SizeOf(AnsiChar);
    CopyMemory(@keyBlob.Data[0], @Key[1], keyBlob.Size);
 
    if CryptImportKey(hCryptProvider, @KeyBlob, SizeOf(KeyBlob), 0, 0, @hKey) then
    begin
      if CryptDuplicateKey(hKey, nil, 0, @hEncryptKey) then
      begin
        if CryptDuplicateKey(hKey, nil, 0, @hDecryptKey) then
        begin
          // Très important, une clé pour Encrypt et une autre pour Decrypt sinon cela fausse le calcul, curieux en ECB cela ne devrait pas, en CBC ou CFB semble tout à fait logique puisque le bloc précédent est utilisé pour le chiffrage du suivant ...
          dwKeyCypherMode := CRYPT_MODE_ECB;
          CryptSetKeyParam(hEncryptKey, KP_MODE, @dwKeyCypherMode, 0);
          CryptSetKeyParam(hDecryptKey, KP_MODE, @dwKeyCypherMode, 0);
 
          Result := Input;
          InputLen := Length(Result) * SizeOf(AnsiChar);
          ResultLen := InputLen;
          if CryptEncrypt(hEncryptKey, 0, AESFinal, 0, nil, @ResultLen, 0) then
          begin
            SetLength(Result, ResultLen);
            pbResult := Pointer(PAnsiChar(Result));
            if CryptEncrypt(hEncryptKey, 0, AESFinal, 0, pbResult, @InputLen, ResultLen) then
            begin
              SetLength(Confirm, ResultLen);
              pbConfirm := Pointer(PAnsiChar(Confirm));
              CopyMemory(pbConfirm, pbResult, ResultLen);
              if CryptDecrypt(hDecryptKey, 0, AESFinal, 0, pbConfirm, @InputLen) then
                SetLength(Confirm, InputLen)
              else
                Confirm := IntToStr(GetLastError());
            end
            else
              Result := IntToStr(GetLastError());
          end;
 
          CryptDestroyKey(hDecryptKey);
        end;
 
        CryptDestroyKey(hEncryptKey);
      end;
 
      CryptDestroyKey(hKey);
    end;
 
    CryptReleaseContext(hCryptProvider, 0);
  end;
end;
J'obtiens presque les bonnes valeurs !
Tout ce joue sur AESFinal qui en censé indiquer la fin du buffer, si l'on crypte un gros buffer, dans mon test, je n'ai qu'un buffer de 128 bits, donc je mets True à bFinal (... Final is set to TRUE for the last or only block ...)

Ce que je ne comprends pas, c'est pourquoi il me génére un Cypher Text de 256 Bits ?
D'après les valeurs de référence, mon texte clair et chiffré sont de même longueur !
J'obtiens bien les bons 128 premiers bits puis 128 bits non prévus !

Si, je mets bFinal à FALSE, j'obtients le bon résultat, juste les 128 bits prévus
Hors, c'est contraire à la documentation ...