0

I'm new in Delphi.I'm trying to make a one-way hashing of an ASCII string. Is there any way to encrypt ASCII string without adding Indy or any other Cryptography library to the project And just by standard functions ?

if there is any way to use windows API , How i can do that ?

if it is possible , please give me an example.

7
  • What's the problem with using third party library? Besides, Indy comes with Delphi. Hint: third party libraries are just code that you didn't have to write yourself. Commented Feb 7, 2014 at 19:51
  • Hashing is pretty easy. Plenty of libraries for that. Have you searched? Commented Feb 7, 2014 at 19:51
  • What did you try? What are requirements for the hash? Questions asking for code should demonstrate a minimum understanding of a problem to be solved. Commented Feb 7, 2014 at 20:02
  • 1
    @alcalde The thing is there is lots of well tried and tested, and simple, C code to implement hashes. It would not take much to compile that to object, and link it. Or even translate to Delphi. But I'd always compile code that is known to work rather then translate. Commented Feb 8, 2014 at 0:02
  • 1
    See MD5 Hashing in Delphi 2009 for an example of hashing an ansistring with Delphi MD5 library MessageDigest_5.pas which is shipped with Delphi since D2009. I noticed that the source is missing by accident in XE3. Commented Feb 8, 2014 at 10:16

2 Answers 2

11

You can use the Windows Cryptography library for this. For instance, here's a minimal unit to calculate MD5 hashes:

unit MD5;

interface

uses
  SysUtils, Math, Windows, Classes;

type
  TMD5Hash = array [0..15] of Byte;

function MD5Hash(Stream: TStream): TMD5Hash; overload;
function MD5Hash(const Bytes: TBytes): TMD5Hash; overload;
function MD5Hash(const Str: RawByteString): TMD5Hash; overload;
function MD5ToString(const Hash: TMD5Hash): string;

implementation

type
  HCRYPTPROV = type NativeUInt;
  HCRYPTKEY = type NativeUInt;
  HCRYPTHASH = type NativeUInt;
  ALG_ID = Cardinal;

const
  PROV_RSA_FULL = 1;
  CRYPT_VERIFYCONTEXT = $F0000000;
  ALG_CLASS_HASH = 4 shl 13;
  ALG_TYPE_ANY = 0;
  ALG_SID_MD5 = 3;
  CALG_MD5 = ALG_CLASS_HASH or ALG_TYPE_ANY or ALG_SID_MD5;
  HP_HASHVAL = $0002;

function CryptAcquireContextW(
  out phProv: HCRYPTPROV;
  pszContainer: PWideChar;
  pszProvider: PWideChar;
  dwProvType: DWORD;
  dwFlags: DWORD
): BOOL; stdcall; external 'Advapi32.dll';

function CryptReleaseContext(
  hProv: HCRYPTPROV;
  dwFlags: DWORD
): BOOL; stdcall; external 'Advapi32.dll';

function CryptCreateHash(
  hProv: HCRYPTPROV;
  Algid: ALG_ID;
  hKey: HCRYPTKEY;
  dwFlags: DWORD;
  out phHash: HCRYPTHASH
): BOOL; stdcall; external 'Advapi32.dll';

function CryptDestroyHash(
  hHash: HCRYPTHASH
): BOOL; stdcall; external 'Advapi32.dll';

function CryptHashData(
  hHash: HCRYPTHASH;
  pbData: Pointer;
  dwDataLen: DWORD;
  dwFlags: DWORD
): BOOL; stdcall; external 'Advapi32.dll';

function CryptGetHashParam(
  hHash: HCRYPTHASH;
  dwParam: DWORD;
  pbData: Pointer;
  var pdwDataLen: DWORD;
  dwFlags: DWORD
): BOOL; stdcall; external 'Advapi32.dll';

function MD5Hash(Stream: TStream): TMD5Hash;
const
  BuffSize = 1024;
var
  hProv: HCRYPTPROV;
  hHash: HCRYPTHASH;
  Buff: array [0..BuffSize] of Byte;
  BytesLeft: Int64;
  BytesToRead: Integer;
  HashSize: DWORD;
begin
  Win32Check(CryptAcquireContextW(hProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT));
  try
    Win32Check(CryptCreateHash(hProv, CALG_MD5, 0, 0, hHash));
    try
      BytesLeft := Stream.Size-Stream.Position;
      while BytesLeft>0 do begin
        BytesToRead := Min(BytesLeft, BuffSize);
        Stream.ReadBuffer(Buff, BytesToRead);
        Win32Check(CryptHashData(hHash, @Buff, BytesToRead, 0));
        dec(BytesLeft, BytesToRead);
      end;
      HashSize := SizeOf(Result);
      Win32Check(CryptGetHashParam(hHash, HP_HASHVAL, @Result, HashSize, 0));
    finally
      Win32Check(CryptDestroyHash(hHash));
    end;
  finally
    Win32Check(CryptReleaseContext(hProv, 0));
  end;
end;

function MD5Hash(const Str: RawByteString): TMD5Hash;
var
  Stream: TStringStream;
begin
  Stream := TStringStream.Create(Str);
  try
    Result := MD5Hash(Stream);
  finally
    Stream.Free;
  end;
end;

function MD5Hash(const Bytes: TBytes): TMD5Hash;
var
  Stream: TBytesStream;
begin
  Stream := TBytesStream.Create(Bytes);
  try
    Result := MD5Hash(Stream);
  finally
    Stream.Free;
  end;
end;

function MD5ToString(const Hash: TMD5Hash): string;
begin
  SetLength(Result, SizeOf(Hash)*2);
  BinToHex(Pointer(@Hash)^, PChar(Result), SizeOf(Hash));
end;

end.
Sign up to request clarification or add additional context in comments.

9 Comments

I must say I am very surprised by the downvote here. I think this is a useful demonstration of how to get a very flexible MD5 with minimal effort. I cannot see how this could be readily improved. I guess the downvote means I got something wrong, and I'd really like to put it right. I can see this answer being referred to in the future. It should be fixed.
Drive-by downvoters. The question itself is +2/-2. I gave you an upvote.
@DavidHeffernan "Minimal effort" to me would be having it built in. :-) Honestly it looks like you put quite a lot of effort into it, including translating function headers. I don't know why the downvote though.
@alcalde Well, I said minimal rather than not very much! ;-) Yes, it took me 30 minutes or so. But it's a straight translation of the MSDN example. And it's a very clean and well-thought our library, so the header translations are simple. I'm not keen on using the JEDI unit because in my experience they come with so much extra baggage.
@LURD these standard hashes are easy enough to implement. I think I will try to write something simple and portable for Delphi
|
4

Zeid, I don't believe it's cryptographically secure, but Delphi does have a hash function called BobJenkinsHash(!!!) in the System.Generics.Defaults unit. It's not user-friendly either (requires you to supply the length (size?) of the memory block you're passing to it and returns an integer value. However, if your requirements are 1) Delphi and 2) no third party libraries and 3) you don't want to implement another hash yourself, I believe it's your only choice.

function BobJenkinsHash(const Data; Len, InitData: Integer): Integer;

You'd need to pass your string as the first parameter, the length of the string * the size of char as the second, and any other number (usually zero) as the last parameter.

1 Comment

Tank you for your time. This is really good answer but David's answer is more useful for me. tank you again for your time and for your sharing.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.