我正在尝试创建此算法的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版本):
(请注意:T256BitArray被定义为字节的数组[0..31])
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;
原始代码段来自Password Safe开源应用程序。
我正在尝试打开现有的密码保存(v3)数据库以供阅读。
似乎无论我做什么我都无法使算法生成所需的哈希值。
在上面的Delphi片段中,我使用的是DEC v5.2 2009组件集。我也尝试过DCPcrypt库。有趣的是,我从两个库中获得了相同的值,但没有任何东西与PWSv3文件中的哈希兼容。
我使用过的SHA256组件都通过了SHA256测试向量哈希值,所以我假设在重新编码方法时我做错了。
我错过了什么吗?
已解决:一切都是正确的。传递密钥字符串的转换问题就出现了。我已经发现我必须使用 WideCharToMultiByte 函数来获得正确的代码页转换。
答案 0 :(得分:0)
下部的循环不应该有wHash.Init;在它。
答案 1 :(得分:0)
我已经解决了这个问题。
我实施的所有内容都是正确的。传递密钥字符串的转换问题就出现了。我已经发现我必须使用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;