当前位置: 首页 > 知识库问答 >
问题:

加密的简单代码。使用密码的INI文件字符串

晁绍辉
2023-03-14

我正在寻找比ROT13更复杂的东西,但它不需要库(最好甚至不需要单元,只需要一个插入html" target="_blank">函数)。

我想使用用户提供的密码对称加密/解密给定的字符串。但是,结果必须是一个字符串,从某种意义上说,我必须能够将其存储在 .INI 文件。

有没有人有一个简单的函数可以做到这一点(delphi XE2)?谷歌今天不是我的朋友。

先谢谢了

[Update]/[Bounty]只是为了澄清(如果最初不是这样,请重复),我不想要哈希。我有一个列表框,用户可以在其中添加/修改/删除条目。我想在程序关闭时将它们存储在. INI文件中,并在程序再次启动时重新加载。任何查看. INI文件的人(例如,在记事本中打开它)都不应该能够读取这些字符串。

我想我可以将组件作为二进制流,但是为了安全起见,我宁愿使用用户提供的密码来加密字符串。对于本应用程序而言,是否并不重要。INI文件段名或keyte值是人类可读的,我只是想加密数据,当存储在磁盘上时,给我一些列表:

[config]
numEntries=3

[listbox]
0=ywevdyuvewfcyuw
1=edw
2=hr4uifareiuf

共有3个答案

贺栋
2023-03-14

我使用的是Delphi Encryption Compendium,它对哈希和对称加密/解密都有很好的功能。它被划分为多个单元,但不需要任何外部库,而且速度非常快。

下面是我在代码中使用它的方法:

function Encrypt(const AStr: string): string;
begin
  Result := AStr;
  with TCipher_Gost.Create do
    try
      Init(THash_SHA1.KDFx('Encryption Key', '', Context.KeySize));
      Result := EncodeBinary(Result, TFormat_HEX);
    finally
      Free;
    end;
end;

function Decrypt(const AStr: string): string;
begin
  Result := AStr;
  with TCipher_Gost.Create do
    try
      Init(THash_SHA1.KDFx('Encryption Key', '', Context.KeySize));
      Result := DecodeBinary(Result, TFormat_HEX);
    finally
      Free;
    end;
end;

您可以使用任何< code>TCipher_*类来代替GOST。

聂风史
2023-03-14

这是Tinifile的替代品。< br> ReadString和WriteString被覆盖,它们是用于Read/WriteFloat、Read/WriteInteger等的内部函数。

字符串被加密并存储为十六进制字符串。

演示用法:

uses CryptingIni;
{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
 ini:TCryptingIni;
begin
    ini:=TCryptingIni.Create('C:\temp\test.ini');
    ini.UseInternalVersion(1234);
    ini.WriteFloat('Sect','Float',123.456);
    ini.WriteString('Sect2','String','How to encode');
    ini.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 ini:TCryptingIni;
begin
    ini:=TCryptingIni.Create('C:\temp\test.ini');
    ini.UseInternalVersion(1234);
    Showmessage(FloatToStr(ini.ReadFloat('Sect','Float',0)));
    Showmessage(ini.ReadString('Sect2','String',''));
    Showmessage(ini.ReadString('SectUnkknow','Showdefault','DEFAULT'));
    ini.Free;
end;

您可以通过UseInternalVersion使用内部加密方法,或使用
Procedure SetCryptingData(aEncryptProc,aDecryptPro:CryptingProc;aKey:Word)提供自己的过程;

unit CryptingIni;

// 2013 by Thomas Wassermann
interface

uses
  Windows, SysUtils, Variants, Classes, inifiles;

type

  CryptingProc = Function(const InString: String; Key: Word): String;

  TCryptingIni = Class(TInifile)
    function ReadString(const Section, Ident, Default: string): string; override;
    procedure WriteString(const Section, Ident, Value: String); override;
  private
    FEncryptProc: CryptingProc;
    FDecryptProc: CryptingProc;
    FKey: Word;
  public
    Procedure SetCryptingData(aEncryptProc, aDecryptProc: CryptingProc; aKey: Word);
    Procedure UseInternalVersion(aKey: Word);
  End;

implementation

const
  c1 = 52845;
  c2 = 22719;

Type
  TByteArray = Array [0 .. 0] of byte;

Function AsHexString(p: Pointer; cnt: Integer): String;
var
  i: Integer;
begin
  Result := '';
  for i := 0 to cnt do
    Result := Result + '$' + IntToHex(TByteArray(p^)[i], 2);
end;

Procedure MoveHexString2Dest(Dest: Pointer; Const HS: String);
var
  i: Integer;
begin
  i := 1;
  while i < Length(HS) do
  begin
    TByteArray(Dest^)[i div 3] := StrToInt(Copy(HS, i, 3));
    i := i + 3;
  end;
end;

function EncryptV1(const s: string; Key: Word): string;
var
  i: smallint;
  ResultStr: string;
  UCS: WIDEString;
begin
  Result := s;
  if Length(s) > 0 then
  begin
    for i := 1 to (Length(s)) do
    begin
      Result[i] := Char(byte(s[i]) xor (Key shr 8));
      Key := (smallint(Result[i]) + Key) * c1 + c2
    end;
    UCS := Result;
    Result := AsHexString(@UCS[1], Length(UCS) * 2 - 1)
  end;
end;

function DecryptV1(const s: string; Key: Word): string;
var
  i: smallint;
  sb: String;
  UCS: WIDEString;
begin
  if Length(s) > 0 then
  begin
    SetLength(UCS, Length(s) div 3 div 2);
    MoveHexString2Dest(@UCS[1], s);
    sb := UCS;
    SetLength(Result, Length(sb));
    for i := 1 to (Length(sb)) do
    begin
      Result[i] := Char(byte(sb[i]) xor (Key shr 8));
      Key := (smallint(sb[i]) + Key) * c1 + c2
    end;
  end
  else
    Result := s;
end;

{ TCryptingIni }

function TCryptingIni.ReadString(const Section, Ident, Default: string): string;
begin
  if Assigned(FEncryptProc) then
    Result := inherited ReadString(Section, Ident, FEncryptProc(Default, FKey))
  else
    Result := inherited ReadString(Section, Ident, Default);
  if Assigned(FDecryptProc) then
    Result := FDecryptProc(Result, FKey);
end;

procedure TCryptingIni.SetCryptingData(aEncryptProc, aDecryptProc: CryptingProc; aKey: Word);
begin
  FEncryptProc := aEncryptProc;
  FDecryptProc := aDecryptProc;
  FKey := aKey;
end;

procedure TCryptingIni.UseInternalVersion(aKey: Word);
begin
  FKey := aKey;
  FEncryptProc := EncryptV1;
  FDecryptProc := DecryptV1;
end;

procedure TCryptingIni.WriteString(const Section, Ident, Value: String);
var
  s: String;
begin
  if Assigned(FEncryptProc) then
    s := FEncryptProc(Value, FKey)
  else
    s := Value;
  inherited WriteString(Section, Ident, s);
end;

end.
陈夜洛
2023-03-14

这个答案中使用的加密算法非常基础,任何具有中等到高密码学技能的个人都可以轻松破解。它被用于解决方案中,因为OP要求一个简单的对称解决方案,而不需要任何库。

该解决方案基于XOR密码。来自维基百科:

在密码学中,简单异或密码是一种加性密码,一种根据以下原则运行的加密算法:

A X 0 = A,

A X A=0,

(A X B) X C = A X (B X C),

(乙 X 甲)X A = B X 0 = B,

其中X表示XOR操作。

我提出的解决方案基于以下基本例程:

function XorCipher(const Key, Source: TBytes): TBytes;
var
  I: Integer;
begin
  if Length(Key) = 0 then
    Exit(Source);
  SetLength(Result, Length(Source));
  for I := Low(Source) to High(Source) do
    Result[I] := Key[I mod Length(Key)] xor Source[I];
end;

该例程接受一个键和源数据作为字节数组,并返回结果xor字节数组。假设在加密和解密操作中使用相同的密钥,则加密和解密信息的例程功能相同。要加密,源是普通数据,要解密,源是加密数据。

我制作了两个辅助例程来允许将结果存储为字符串。一个用于将字节数组转换为十六进制数字的文本序列,另一个用于执行反向转换:

function BytesToStr(const Bytes: TBytes): string;
var
  I: Integer;
begin
  Result := '';
  for I := Low(Bytes) to High(Bytes) do
    Result := Result + LowerCase(IntToHex(Bytes[I], 2));
end;

function StrToBytes(const value: string): TBytes;
var
  I: Integer;
begin
  SetLength(Result, Length(value) div 2);
  for I := Low(Result) to High(Result) do
    Result[I] := StrToIntDef('$' + Copy(value, (I * 2) + 1, 2), 0);
end;

有了这个基础,你就可以建造你所需要的一切。为了方便和测试我的代码,我创建了一些其他的例程,例如:

>

  • 这个将密钥存储在exe中,并将其作为TBytes值获取

    function GetKey: TBytes;
    begin
      Result := TArray<Byte>.Create(
         $07, $14, $47, $A0, $F4, $F7, $FF, $48, $21, $32
       , $AF, $87, $09, $8E, $B3, $C0, $7D, $54, $45, $87
       , $8A, $A8, $23, $32, $00, $56, $11, $1D, $98, $FA
      );
    end;
    

    您可以提供任意长度的密钥,因为它可以加密XorCipher例程中的数据。

    这个函数使用那个键对给定的字符串进行正确的编码:

    function XorEncodeStr(const Source: string): string; overload;
    var
      BSource: TBytes;
    begin
      SetLength(BSource, Length(Source) * SizeOf(Char));
      Move(Source[1], BSource[0], Length(Source) * SizeOf(Char));
      Result := XorEncodeToStr(GetKey, BSource);
    end;
    

    这个其他将编码的字符串正确解码为字符串

    function XorDecodeStr(const Source: string): string; overload;
    var
      BResult: TBytes;
    begin
      BResult := XorDecodeFromStr(GetKey, source);
      Result := TEncoding.Unicode.GetString( BResult );
    end;
    

    使用您写入和读取INI文件的地方可以访问此例程,您可以轻松地写入和读取它,例如:

    procedure TForm1.SaveIni;
    var
      Ini: TIniFile;
      I: Integer;
    begin
      Ini := TIniFile.Create('.\config.ini');
      try
        Ini.WriteInteger('config', 'NumEntries', ListBox1.Items.Count);
        for I := 0 to ListBox1.Items.Count - 1 do
          Ini.WriteString('listbox', IntToStr(I), XorEncodeStr(listbox1.Items[I]));
      finally
        Ini.Free;
      end;
    end;
    
    procedure TForm1.LoadIni;
    var
      Ini: TIniFile;
      Max, I: Integer;
    begin
      ListBox1.Items.Clear;
      Ini := TIniFile.Create('.\config.ini');
      try
        Max := Ini.ReadInteger('config', 'NumEntries', 0);
        for I := 0 to Max - 1 do
          ListBox1.Items.Add(
            XorDecodeStr(Ini.ReadString('listbox', IntToStr(I), ''))
          );
      finally
        Ini.Free;
      end;
    end;
    

    这不是生产就绪代码,因为它只是为了测试解决方案而编写的,但它也是您使其坚如磐石的起点。

    这不是强大的加密技术,所以,不要依赖它来存储真正敏感的信息。一个弱点是密钥以普通形式包含在您的 exe 中。你可以解决这个问题,但主要的弱点是算法本身。

    以以下问题为例:由于您使用UTF-16格式编码Unicode Delphi字符串,因此每个字符的第二个字节通常为零(除非您在东部或使用非拉丁字母的国家),您将在编码的存储字符串中找到密钥重复的确切字节。您可以通过不使用编码数据的普通十六进制表示(例如,这里已经建议使用base64对其进行编码)来减少这一点。

    您可以使用AnsiStrings来避免泄露密钥的这一部分,也可以在偶数位置使用显式零字节(或其他常量字节)对密钥进行编码。

    如果你的软件的用户没有受过密码学教育,这一切都可以工作,但事实是,任何具有中等知识水平和良好技能的人都可以通过分析你的数据获得密钥。如果用户知道一个未编码的值,事情会变得更容易。

  •  类似资料:
    • 下面是我的Bean类 当我运行代码时,我得到了下面的错误,字段passwordEncoder在com.naveen.controller.UserController需要一个类型为'PasswordEncoder'的beancom.naveen.entity.找不到。注入点有以下注释:-@org.springframework.beans.factory.annotation.自动加载(必需=tr

    • 问题内容: 我正在使用JConsole访问我的应用程序MBean,并且使用了password.properties文件。但是根据Sun的规范,此文件仅包含明文格式的密码。 现在,我想对密码进行加密并将其用于JConsole的JMX用户身份验证(“远程”部分中的“用户名”和“密码”字段)。我可以使用任何预定义的加密逻辑或自己的加密算法。 是否有人知道将这种纯文本密码更改为加密密码,这样JMX Fra

    • 假设我有一个IP地址,192.168.1.1 我想让我的程序基于这个IP地址创建一个随机的单字字符串,它可以很容易地解密,而无需密钥或密码或额外的安全措施。 例如。 我进入192.168.1.1 程序将其转换为AzlQrEHCSD或其他一些随机字符串 我在程序中输入这个字符串 它被转换回192.168.1.1 有没有简单的算法可以在不生成密钥或其他密码的情况下做到这一点?我知道密钥和密码是加密和解

    • 我正在一个smal家庭项目中工作,我需要加密用户输入的文本。文本文件是在程序def personal_save()的第一部分创建的:但是我想要实现的是,当用户按下主页上的关闭按钮时,def file_Encryption读取生成的txt文件并对其进行加密。我已经找到了一个代码与简单的加密,并试图改变代码,但没有运气,因为我是新的编程世界。 我已经创建了一个函数,当用户按下退出按钮时,文件应该用静态

    • 简单替换密码是最常用的密码,包括为每个密文文本字符替换每个纯文本字符的算法。 在这个过程中,与凯撒密码算法相比,字母表是混乱的。 例子 (Example) 简单替换密码的密钥通常由26个字母组成。 一个示例关键是 - plain alphabet : abcdefghijklmnopqrstuvwxyz cipher alphabet: phqgiumeaylnofdxjkrcvstzwb 使用

    • 我目前正在学习Ruby,并尝试过简单密码挑战。我现在正在研究下面的解决方案,并试图通过逆向工程来理解这个解决方案背后的思维过程。以下是解决方案的链接。我将详细说明我对每个代码段的理解。如果他们不对,你能纠正我吗?谢了!https://extrym.io/tracks/ruby/extryes/simple-cipher/solutions/B200C3D9F10E497BBE2CA0D826DF2