Question

I found a simple unit for generating a RSA KeyPair and encrypting / decrypting. It works fine on small strings but on larger text I get error : Bad Length.

What could be the cause , here is the unit, the unit wcrypt2 you can download here

Tested on Delphi 2010

unit Crypt_RSA;

interface

uses
  Windows, Classes, SysUtils, WCrypt2;

function RSAGenerateKeys(var PrivateKey, PublicKey: String): Boolean;
function RSAEncrypt(Source, Key: String): String;
function RSADecrypt(Source, Key: String): String;

implementation

function RSAGenerateKeys(var PrivateKey, PublicKey: String): Boolean;
const
  RSA1024BIT_KEY = $04000000;

var
  RSA: HCRYPTPROV;
  HKeyPair: HCRYPTKEY;
  Pair: TStringStream;
  buflen: DWORD;

  function SetKey(BlobDef: Cardinal; var Key: String): Boolean;
  begin
    Result := Bool(CryptExportKey(HKeyPair, 0, BlobDef, 0, nil, @buflen));
    if Result then
    begin
      Pair.SetSize(buflen);
      Result := Bool(CryptExportKey(HKeyPair, 0, BlobDef, 0, PByte(Pair.Memory), @buflen));
    end;

    Key := Pair.ReadString(buflen);
    Pair.Seek(0, soBeginning);
  end;

begin
  Pair := TStringStream.Create;

  Result := Bool(CryptAcquireContext(@RSA, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT));
  if Result then
    Result := Bool(CryptGenKey(RSA, AT_KEYEXCHANGE, RSA1024BIT_KEY or CRYPT_EXPORTABLE, @HKeyPair));

  if Result then
    Result := SetKey(PRIVATEKEYBLOB, PrivateKey);
  if Result then
    Result := SetKey(PUBLICKEYBLOB, PublicKey);

  CryptDestroyKey(HKeyPair);
  CryptReleaseContext(RSA, 0);
  FreeAndNil(Pair);
end;

function RSAEncrypt(Source, Key: String): String;
var
  KeyPair: TStringStream;
  RSA: HCRYPTPROV;
  HPair: HCRYPTKEY;
  DDataSize, EDataSize: DWORD;

begin
  Result := '';
  KeyPair := TStringStream.Create(Key);
  if CryptAcquireContext(@RSA, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) then
  try
    if CryptImportKey(RSA, PByte(KeyPair.Memory), KeyPair.Size, 0, 0, @HPair) then
    try
      EDataSize := SizeOf(Source);
      if CryptEncrypt(HPair, 0, true, 0, nil, @EDataSize, 0) then
      begin
        Result := Source;
        SetLength(Result, EDataSize);
        DDataSize := Length(Source) * SizeOf(Char);
        if not(CryptEncrypt(HPair, 0, True, 0, PByte(PChar(Result)), @DDataSize, EDataSize)) then
          Result := '';
      end;
    finally
      CryptDestroyKey(HPair);
    end;
  finally
  CryptReleaseContext(RSA, 0);
  end;
  FreeAndNil(KeyPair);
end;

function RSADecrypt(Source, Key: String): String;
var
  KeyPair: TStringStream;
  RSA: HCRYPTPROV;
  HPair: HCRYPTKEY;
  EDataSize: DWORD;

begin
  KeyPair := TStringStream.Create(Key);
  Result := '';
  if CryptAcquireContext(@RSA, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) then
  try
    if CryptImportKey(RSA, PByte(KeyPair.Memory), KeyPair.Size, 0, 0, @HPair) then
    try
      Result := Source;
      EDataSize := Length(Result);
      if not Bool(CryptDecrypt(HPair, 0, True, 0, PByte(PChar(Result)), @EDataSize)) then
        EDataSize := 0;
      SetLength(Result, EDataSize div SizeOf(Char));
    finally
      CryptDestroyKey(HPair);
    end;
  finally
    CryptReleaseContext(RSA, 0);
  end;
  FreeAndNil(KeyPair);
end;

end.
Was it helpful?

Solution

C# in a Nutshell says that plaintext much longer than 1/2 the key size will cause an error. It's likely the same for most languages for security purposes. For longer messages, use RSA to pass a key for symmetrical encryption such as AES.

OTHER TIPS

Asymmetric encryption limits the data to less than the key size, there is padding such as OAEP which is 42 bytes.

If you must have asymmetric encryption, that is need a key pair, use hybrid encryption which is essentially what https does. See Hybrid cryptosystem.

For Hybrid encryption basically you create a random symmetric encryption key, encrypt the symmetric key with an asymmetric encryption, encrypt the data with the symmetric key and package the two encryptions together.

Why don't you want symmetric encryption? It is much faster and handles essentially any data size? AES is the encryption workhorse.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top