Delphi 10.4加密密码存入Firebird后字符异常的技术求助
问题排查与解决方案
核心原因:你加密后的结果本质是二进制字节流,而非合法的文本字符,当用字符串类型存储时,Delphi的Unicode字符串与Firebird的字符集编码映射过程中,无效或无法映射的字节被替换成了其他字符(比如¥变成Y)。
解决方法(按推荐优先级排序)
1. 转Base64存储(最稳妥的文本方式)
加密后的二进制数据转成Base64编码的字符串,所有字符都是可打印的安全字符,不会出现编码转换问题:
修改加密/解密函数
uses System.NetEncoding; // 加密:输入字符串,返回加密后的字节数组 function Titkositas(Jelszo: string; Code: LongInt): TBytes; var Ciklus: Integer; JelszoBytes: TBytes; begin RandSeed := Code; // 先把输入密码转成UTF-8字节(避免Unicode字符丢失) JelszoBytes := TEncoding.UTF8.GetBytes(Jelszo); SetLength(Result, Length(JelszoBytes)); for Ciklus := 0 to High(JelszoBytes) do Result[Ciklus] := JelszoBytes[Ciklus] xor Random(256); end; // 解密:输入加密后的字节数组,返回原始密码字符串 function Dekodolas(EncryptedBytes: TBytes; Code: LongInt): string; var Ciklus: Integer; DecryptedBytes: TBytes; begin RandSeed := Code; SetLength(DecryptedBytes, Length(EncryptedBytes)); for Ciklus := 0 to High(EncryptedBytes) do DecryptedBytes[Ciklus] := EncryptedBytes[Ciklus] xor Random(256); Result := TEncoding.UTF8.GetString(DecryptedBytes); end;
存储与验证代码
// 存储时转Base64 ParamByName('PASSWD').AsString := TBase64Encoding.EncodeBytesToString(Titkositas(Trim(Edit4.Text), 123456)); // 验证时解码Base64再解密 var EncryptedBase64: string; EncryptedBytes: TBytes; begin // 从数据库读取PASSWD字段值 EncryptedBase64 := Query1.FieldByName('PASSWD').AsString; EncryptedBytes := TBase64Encoding.DecodeStringToBytes(EncryptedBase64); if Dekodolas(EncryptedBytes, 123456) = Trim(EditLoginPassword.Text) then ShowMessage('登录成功') else ShowMessage('密码错误'); end;
2. 用二进制字段存储(最直接的方式)
将Firebird表的PASSWD字段类型改为BLOB SUB_TYPE BINARY,直接存储加密后的字节数组,跳过编码转换:
存储与验证代码
// 存储时直接存字节 ParamByName('PASSWD').AsBytes := Titkositas(Trim(Edit4.Text), 123456); // 验证时直接读字节解密 var EncryptedBytes: TBytes; begin EncryptedBytes := Query1.FieldByName('PASSWD').AsBytes; if Dekodolas(EncryptedBytes, 123456) = Trim(EditLoginPassword.Text) then ShowMessage('登录成功'); end;
3. 强制编码一致性(不推荐,仍有风险)
如果坚持用字符串字段,需确保两端编码完全匹配:
- Firebird表的
PASSWD字段设为VARCHAR(n) CHARACTER SET UTF8,n要足够大 - Delphi端用
AsWideString传递参数,避免编码转换:ParamByName('PASSWD').AsWideString := Titkositas(Trim(Edit4.Text), 123456);
注意:这种方式仍可能因为某些字节序列不是合法UTF-8字符而被替换,导致数据损坏,仅作为临时过渡方案。
内容的提问来源于stack exchange,提问作者Hexa
相关产品推荐
相关产品推荐

