1

Topic: Microsoft CrytoAPI and RSA

Nobody knows, how function CryptDecrypt in MS CryptoAPI works?
Problem in the following: I need to cipher certain given by algorithm RSA with key length 1024 bits that then they could be decrypted through CryptoAPI. At present I have the following code (cut all superfluous):
In CryptoAPI key pair RSA is generated and the public key is exported

...
CryptGenKey (FProvider, AT_KEYEXCHANGE, 1024 shl 16, FUserKeyPair);
CryptExportKey (FUserKeyPair, 0, PUBLICKEYBLOB, 0, @Key [0], BlobSize);
...

Then preempted key shares on an exponent and the unit:

procedure ExtractPublicKey (Blob: PByte; BlobSize: Integer; E, N: TBigNum);
var
PubKeyHdr: TPublicKeyStruc;
RsaPubKey: TRsaPubKey;
ModSize: Integer;
begin
if BlobSize <SizeOf (RsaPubKey) + SizeOf (PubKeyHdr) then
raise Exception. Create (' Invalid size of PUBLICKEYBLOB. ');
Move (Blob ^, PubKeyHdr, SizeOf (PubKeyHdr));
Inc (Blob, SizeOf (PubKeyHdr));
Move (Blob ^, RsaPubKey, SizeOf (RsaPubKey));
Inc (Blob, SizeOf (RsaPubKey));
ModSize: = RsaPubKey.bitlen shr 3;
if ModSize> BlobSize - SizeOf (RsaPubKey) - SizeOf (PubKeyHdr) then
raise Exception. Create (' Invalid size of PUBLICKEYBLOB. ');
E.CopyDigit (RsaPubKey.pubexp);
N.CopyBytes (Blob, ModSize);
end;

Since in the function description CryptDecrypt it is told that it uses PKCS #1 Padding implemented it thus:

function PKCS1Padding (Data: Pointer; Size: Integer; BitLen: Integer): TBytes;
var
Bound: Integer;
Index: Integer;
begin
if (BitLen mod 8> 0) or (Size + 11> BitLen shr 3) then
raise Exception. Create (' Invalid bit length or data is too large. ');
Bound: = BitLen shr 3;
SetLength (Result, Bound);
PWord (Result) ^: = $0200;
Dec (Bound, Size);
for Index: = 2 to Bound - 1 do
Result [Index]: = 1 + Byte (Random (255));
Result [Bound]: = $00;
Move (Data ^, Result [Bound + 1], Size);
end;

C enciphering looks somehow so:

var
Message: string;
PubKey: TBytes;
Binary: TBytes;
MsgNum: TBigNum;
...
CAPI.PublicKeyExport (PubKey);//CAPI -  a wrapper over CryptoAPI
//RSA - class RSA from library uCrypto: https://github.com/arkusuma/uCrypto
ExtractPublicKey (PByte (PubKey), Length (PubKey), RSA.E, RSA.N);
Binary: = PKCS1Padding (PByte (Message), Length (Message) * SizeOf (Char), 1024);
MsgNum: = TBigNum. CreateBytes (PByte (Binary), Length (Binary));
try
Assert (MsgNum. Compare (RSA.N) <0, ' M must be in range of 0. N-1 ');
RSA.Encrypt (MsgNum);//inline-function for call MsgNum. PowMod (E, N);
...

And as a result at text decryption during this moment we receive NTE_BAD_DATA:

...
if not CryptDecrypt (FUserKeyPair, 0, TRUE, 0, Data, DataSize) then
RaiseLastOSErrorEx (sFailedDecryption);
...

Enciphering and decryption that in uCrypto that in CryptoAPI work normally if to decrypt in the same library in what it is ciphered. And here is how them to force to work among themselves? Probably somebody knows any nuances which I missed?
P.S: Enciphering is required  without CryptoAPI since as a result the data can be ciphered there where it is not present (linux, etc), at present it not working application, and the test bed where I try to understand as it generally works.

2

Re: Microsoft CrytoAPI and RSA

, understood, the data after PKCS1Padding () needed to be turned...

3

Re: Microsoft CrytoAPI and RSA

alekcvp;
Would add...

4

Re: Microsoft CrytoAPI and RSA

makhaon wrote:

alekcvp;
Would add...

There there is nothing to add, one line to change (BE = Big-Endian):

MsgNum: = TBigNum. CreateBytes>>> BE <<<(PByte (Binary), Length (Binary));

After that all works. Simply I when experimented the unit tried so to load, did not help. And it appears it was necessary to turn the message, since it on-default in Big-Endian a format.