代码之家  ›  专栏  ›  技术社区  ›  Vivian Mills

“StretchKey”实现有什么问题?

  •  2
  • Vivian Mills  · 技术社区  · 16 年前

    我正在尝试创建此算法的Delphi版本:

    void PWSfileV3::StretchKey(const unsigned char *salt, unsigned long saltLen,
                               const StringX &passkey,
                               unsigned int N, unsigned char *Ptag)
    {
      /*
      * P' is the "stretched key" of the user's passphrase and the SALT, as defined
      * by the hash-function-based key stretching algorithm in
      * http://www.schneier.com/paper-low-entropy.pdf (Section 4.1), with SHA-256
      * as the hash function, and N iterations.
      */
      int passLen = 0;
      unsigned char *pstr = NULL;
    
      ConvertString(passkey, pstr, passLen);
      unsigned char *X = Ptag;
      SHA256 H0;
      H0.Update(pstr, passLen);
      H0.Update(salt, saltLen);
      H0.Final(X);
    
    #ifdef UNICODE
      trashMemory(pstr, passLen);
      delete[] pstr;
    #endif
    
      ASSERT(N >= MIN_HASH_ITERATIONS); // minimal value we're willing to use
      for (unsigned int i = 0; i < N; i++) {
        SHA256 H;
        // The 2nd param in next line was sizeof(X) in Beta-1
        // (bug #1451422). This change broke the ability to read beta-1
        // generated databases. If this is really needed, we should
        // hack the read functionality to try both variants (ugh).
        H.Update(X, SHA256::HASHLEN);
        H.Final(X);
      }
    }
    

    void ConvertString(const StringX &text,
                       unsigned char *&txt,
                       int &txtlen)
    {
      LPCTSTR txtstr = text.c_str(); 
      txtlen = text.length();
    
    #ifndef UNICODE
      txt = (unsigned char *)txtstr; // don't delete[] (ugh)!!!
    #else
    #ifdef _WIN32
      txt = new unsigned char[3*txtlen]; // safe upper limit
      int len = WideCharToMultiByte(CP_ACP, 0, txtstr, txtlen,
        LPSTR(txt), 3*txtlen, NULL, NULL);
      ASSERT(len != 0);
    #else
      mbstate_t mbs;
      memset(&mbs, '\0', sizeof(mbs));
      size_t len = wcsrtombs(NULL, &txtstr, 0, &mbs);
      txt = new unsigned char[len+1];
      len = wcsrtombs((char *)txt, &txtstr, len, &mbs);
      ASSERT(len != (size_t)-1);
    #endif
      txtlen = len;
      txt[len] = '\0';
    #endif /* UNICODE */
    }
    

    以下是我得到的(D2009版本):

    procedure StretchKey(Const Salt:T256BitArray; Const Passkey:string; Const Iterations:LongWord; Var KeyResult:T256BitArray);
    var
       pStr : RawByteString;
       wHash : THash_sha256;
       loop : integer;
    begin
      pStr := AnsiString(PassKey);
    
      wHash := THash_SHA256.Create;
      try
         wHash.Init;
         wHash.Calc(pStr[1], Length(pStr));
         wHash.Calc(Salt, Length(Salt));
         wHash.Done;
         PStr := wHash.DigestStr;
      finally
         FreeAndNil(wHash);
      end;
    
      for loop := 0 to Iterations-1 do
      begin
         wHash := THash_sha256.Create;
         try
            wHash.Init;
            wHash.Calc(PStr[1], wHash.DigestSize);
            wHash.Done;
            PStr := wHash.DigestStr;
         finally
            FreeAndNil(wHash);
         end;
      end;
    
      move(pStr[1], KeyResult, sizeof(KeyResult));
    end;
    

    我正试图打开现有的密码保存(v3)数据库进行读取。

    在上面的Delphi代码片段中,我使用的是DEC v5.2 2009组件集。我还尝试了DCPcrypt库。有趣的是,我从两个库中得到了相同的值,但没有任何结果与PWSv3文件中的散列兼容。

    我使用的SHA256组件都通过了SHA256测试向量散列,所以我假设我在重新编码方法时出错了。

    我错过什么了吗?

    解决了的 字体一切都是正确的。问题出现在密钥字符串的转换中。我发现我必须使用 宽图表多字节

    2 回复  |  直到 16 年前
        1
  •  0
  •   Brian Evans    16 年前

    下部的循环不应该有wHash.Init;在里面。

        2
  •  0
  •   Vivian Mills    16 年前

    我已经解决了这个问题。

    我的实现一切都是正确的。问题出现在密钥字符串的转换中。我发现我必须使用WideCharToMultiByte函数来获得正确的代码页转换。

    procedure StretchKey(Const Salt:T256BitArray; Const Passkey:string; Const Iterations:LongWord; Var KeyResult:T256BitArray);
    var
       pStr : RawByteString;
       wHash : THash_sha256;
       loop : integer;
       wStr : AnsiString;
       wLen : integer;
    begin
      wLen := 3*length(PassKey);
      SetLength(wStr, wLen);
    
      wLen := WideCharToMultiByte(GetACP, 0, PChar(PassKey), length(PassKey), PAnsiChar(wStr), wLen, nil, nil);
      SetLength(wStr, wLen);
    
      pStr := wStr;
    
      wHash := THash_SHA256.Create;
      try
         wHash.Init;
         wHash.Calc(pStr[1], Length(pStr));
         wHash.Calc(Salt, Length(Salt));
         wHash.Done;
         PStr := wHash.DigestStr;
      finally
         FreeAndNil(wHash);
      end;
    
      for loop := 0 to Iterations-1 do
      begin
         wHash := THash_sha256.Create;
         try
            wHash.Init;
            wHash.Calc(PStr[1], wHash.DigestSize);
            wHash.Done;
            PStr := wHash.DigestStr;
         finally
            FreeAndNil(wHash);
         end;
      end;
    
      move(pStr[1], KeyResult, sizeof(KeyResult));
    end;