Andrew Jones
Andrew Jones

Reputation: 1001

Using iSeries cryptographic APIs with BouncyCastle

I'm attempting to encrypt comms between a C# client and iSeries server but am experiencing some issues. I'm trying to use Diffie Hellman to create a shared secret but the shared secret is not matching.

I'm using Bouncy Castle in the C# and the QC3* APIs on the iSeries. The steps are:

  1. C# client generates DH parameters and sends them to the server along with the client public key.
  2. C service program decodes the parameters and calls QC3GENDK to create server public key.
  3. Server calls QC3CALDS with the client public key to generate the shared secret.
  4. Server public key is sent back to the client.
  5. Bouncy Castle Basic DH agreement initialized with the client private key
  6. Client calls CalculateAgreement with the DHPublicKeyParameters generated from the parameters in step 1 and the server public key.

The way the data is sent back and forth is by converting to HEX strings and decoding on each side. Conversion between EBCDIC and ASCII occurs in a service program on the iSeries. So for example, the client public key is converted as follows:

  1. Public key (as BigInteger) is converted to unsigned byte array, e.g. 256 -> { 1, 0 }
  2. Byte array is converted to a string of HEX characters, e.g. { 1, 0 } -> "0100")
  3. HEX string sent across to iSeries.
  4. HEX string converted to a character array of length 64 via the following (RPG) code:

    cvtch( %Addr (@clientKey ): %Addr(data4): 128);
    eval @clientKey = %Subst( @clientKey: 1: 64);
    

    where:

    data4 - HEX string

    @clientKey - 64A receiver variable

and the server key is converted to Hex via:

  1. Convert to hex string on the server

    cvthc ( %Addr( @serverKeyHex ): %Addr(@serverKey): 128);
    eval @serverKeyHex = %Subst(@serverKeyHex: 1: 128);
    

    where:

    @serverKey is the 64A serverKey

    @serverKeyHex is the 128A receiver variable

  2. Send the HEX string across to C# client

  3. Interpret the HEX string as a BigInteger via

    var serverKey = new BigInteger(serverHex, 16);

So, the shared secret isn't matching but I don't know if this is to do with how I'm interpreting the keys or sending them across. Thanks for any suggestions.

EDIT: To give a concrete example:

In the RPG debugger I can see: RPG debugger

For a Client public key whose hex is : 4F58E1463B66CAAC1BDD35C518A6B76E52E0464E635050B50C87329CFC4C154B8EA07B12AF0E0B9754D5331235805CF59ABE1BB500B4906BD03BCF6C7861E2E8

EDIT2 (More info): API calls on the iSeries (in C) can be seen in this gist: https://gist.github.com/ximenean/a0a9193b776f301997bb

Upvotes: 2

Views: 335

Answers (1)

Buck Calabro
Buck Calabro

Reputation: 7648

I don't know what conversion is happening on the C# side, but the RPG / MI side is converting from string to string. Take an EBCDIC string 'ABCD' This is a perfectly valid 4 byte binary number, as well as a perfectly valid 4 byte character. In EBCDIC CCSID 37 (US English), this string has the code points x'C1C2C3C4'.

CVTCH will generate the following string: 'C1C2C3C4' That is, it takes a 4 character string and 'converts' it to an 8 character string. In CCSID 37, that is x'C3F1C3F2C3F3C3F4'. If you send this string off to a client which interprets this in ASCII, it will be interpreted quite differently, as ASCII's code points x'C1C2C3C4' is the ASCII string 'ÁÂÃÄ'

You probably want to translate it to ASCII before sending it from the IBM side. 'C1C2C3C4' would become '41424344' and so on.

Upvotes: 2

Related Questions