Windows Crypto Api糟糕的长度

时间:2013-02-04 14:53:13

标签: delphi cryptoapi

我发现了一个用于生成RSA KeyPair和加密/解密的简单单元。它在小字符串上工作正常但在较大的文本上我得到错误:Bad Length。

可能是什么原因,这是单位,你可以下载单位wcrypt2 here

在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.

2 个答案:

答案 0 :(得分:0)

Nuts中的C#表示明文比密钥大小的1/2长得多会导致错误。出于安全目的,大多数语言可能都是一样的。对于较长的消息,请使用RSA传递密钥以进行对称加密,例如AES。

答案 1 :(得分:0)

非对称加密将数据限制为小于密钥大小,OAEP等填充为42字节。

如果您必须使用非对称加密,则需要密钥对,请使用混合加密,这实质上是https所做的。请参阅Hybrid cryptosystem

对于混合加密,基本上您可以创建随机对称加密密钥,使用非对称加密对对称密钥进行加密,使用对称密钥加密数据并将两个加密打包在一起。

为什么不想要对称加密?它更快,基本上处理任何数据大小? AES是加密的主力。