如何用Delphi 10的THashSHA2实现Drupal 7密码认证?
完全可以用THashSHA2复现Drupal 7的这个哈希认证流程——Drupal 7默认采用SHA-512作为哈希算法,刚好对应THashSHA2的SHA512实现,核心是精准模拟PHP中字节级的拼接与重复哈希逻辑,具体实现思路如下:
初始哈希计算
将PHP代码里的salt . password字符串拼接逻辑转为Delphi的字节流操作:先把salt和password字符串按UTF-8编码转为字节数组,拼接成一个新的字节数组;然后实例化THashSHA2并指定SHA512算法,计算该字节数组的哈希值,得到原始字节形式的初始哈希结果(对应PHP中hash($algo, $salt . $password, TRUE)的输出)。循环哈希迭代
严格遵循PHP的do-while循环逻辑:每次将上一轮生成的哈希字节数组,与password的UTF-8字节数组拼接,再用THashSHA2重新计算哈希并覆盖原有结果,重复执行指定的count次(注意PHP中是先执行一次循环再递减count,Delphi中要保证循环次数完全匹配)。适配Drupal自定义Base64编码
Drupal 7的_password_base64_encode是修改过的Base64编码(替换了标准Base64的+为.、/为_,并去除末尾的=),需要自行实现这个编码函数,将最终的哈希字节数组按此规则编码。拼接最终结果
将Drupal的setting字符串(包含算法标识、迭代次数、salt等信息)与编码后的哈希字符串拼接,得到和Drupal存储格式一致的密码哈希串,用于后续认证比对。
核心代码示例
function DrupalPasswordCrypt(const SaltSetting, Password: string; IterationCount: Integer): string; var HashSHA2: THashSHA2; Salt: string; InitialBytes, PasswordBytes, HashBytes: TBytes; I: Integer; begin // 从SaltSetting中提取实际salt(需自行解析Drupal的setting格式) Salt := ExtractSaltFromSetting(SaltSetting); PasswordBytes := TEncoding.UTF8.GetBytes(Password); InitialBytes := TEncoding.UTF8.GetBytes(Salt) + PasswordBytes; HashSHA2 := THashSHA2.Create(SHA512); try // 初始哈希计算 HashBytes := HashSHA2.ComputeHash(InitialBytes); // 执行指定次数的迭代哈希 for I := 1 to IterationCount do begin HashBytes := HashSHA2.ComputeHash(HashBytes + PasswordBytes); end; // 应用Drupal自定义Base64编码 Result := SaltSetting + DrupalCustomBase64Encode(HashBytes); finally HashSHA2.Free; end; end; // 需自行实现的辅助函数示例 function DrupalCustomBase64Encode(const Input: TBytes): string; var S: string; begin S := TNetEncoding.Base64.EncodeBytesToString(Input); // 替换字符并去除末尾等号 S := StringReplace(S, '+', '.', [rfReplaceAll]); S := StringReplace(S, '/', '_', [rfReplaceAll]); S := StringReplace(S, '=', '', [rfReplaceAll]); Result := S; end;
内容的提问来源于stack exchange,提问作者Ephraim

