【问题标题】:Using iSeries cryptographic APIs with BouncyCastle将 iSeries 加密 API 与 BouncyCastle 一起使用
【发布时间】:2014-11-10 09:56:55
【问题描述】:

我正在尝试加密 C# 客户端和 iSeries 服务器之间的通信,但遇到了一些问题。我正在尝试使用 Diffie Hellman 创建共享密钥,但共享密钥不匹配。

我在 C# 中使用 Bouncy Castle,在 iSeries 上使用 QC3* API。步骤是:

  1. C# 客户端生成 DH 参数并将它们与客户端公钥一起发送到服务器。
  2. C服务程序解码参数并调用QC3GENDK创建服务器公钥。
  3. 服务器使用客户端公钥调用 QC3CALDS 以生成共享密钥。
  4. 服务器公钥被发送回客户端。
  5. 使用客户端私钥初始化的 Bouncy Castle Basic DH 协议
  6. 客户端使用根据第 1 步中的参数和服务器公钥生成的 DHPublicKeyParameters 调用 CalculateAgreement。

数据来回发送的方式是转换为 HEX 字符串并在每一侧进行解码。 EBCDIC 和 ASCII 之间的转换发生在 iSeries 上的服务程序中。所以例如客户端公钥转换如下:

  1. 公钥(作为 BigInteger)被转换为无符号字节数组,例如256 -> { 1, 0 }
  2. 字节数组转换为十六进制字符串,例如{ 1, 0 } -> "0100")
  3. 十六进制字符串发送到 iSeries。
  4. 通过以下 (RPG) 代码将十六进制字符串转换为长度为 64 的字符数组:

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

    地点:

    data4 - 十六进制字符串

    @clientKey - 64A 接收者变量

服务器密钥通过以下方式转换为十六进制:

  1. 在服务器上转换为十六进制字符串

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

    地点:

    @serverKey 是 64A serverKey

    @serverKeyHex 是 128A 接收器变量

  2. 将 HEX 字符串发送到 C# 客户端

  3. 将 HEX 字符串解释为 BigInteger via

    var serverKey = new BigInteger(serverHex, 16);

所以,共享密钥不匹配,但我不知道这是否与我如何解释密钥或发送密钥有关。感谢您的任何建议。

编辑: 举个具体的例子:

在 RPG 调试器中,我可以看到:

对于十六进制为 4F58E1463B66CAAC1BDD35C518A6B76E52E0464E635050B50C87329CFC4C154B8EA07B12AF0E0B9754D5331235805CF59ABE1BB500B4906BD03BCF6C76 的客户端公钥

EDIT2(更多信息): iSeries 上的 API 调用(用 C 语言)可以在这个要点中看到: https://gist.github.com/ximenean/a0a9193b776f301997bb

【问题讨论】:

  • 在第 3 点 -- HEX string sent across to iSeries. 值是如何来回“发送”的?另外,我们可以在您的 iSeries 上查看 API 调用吗?
  • @user2338816 我添加了 API 调用的要点。数据通过 TCP/IP 发送 - 服务程序侦听套接字并将原始字节转换为 EBCDIC 字符串。
  • 我会查看您的 API。为了强调其他人所说的,这是不是 EBCDIC 数据(也不是ASCII)。必须注意将其视为二进制数据,即不能进行任何类型编码或进行其他转换的位串。如果它在 PC 上的位级别与在您的 iSeries 调试中相同,那么到目前为止,很好。

标签: c# bouncycastle ibm-midrange


【解决方案1】:

我不知道 C# 端发生了什么转换,但 RPG / MI 端正在从字符串转换为字符串。取一个 EBCDIC 字符串 'ABCD' 这是一个完全有效的 4 字节二进制数,也是一个完全有效的 4 字节字符。在 EBCDIC CCSID 37(美国英语)中,此字符串具有代码点 x'C1C2C3C4'。

CVTCH 将生成以下字符串:'C1C2C3C4' 即,它需要一个 4 个字符的字符串并将其“转换”为一个 8 个字符的字符串。在 CCSID 37 中,即 x'C3F1C3F2C3F3C3F4'。如果你把这个字符串发送给一个用 ASCII 解释这个字符串的客户端,它的解释会完全不同,因为 ASCII 的代码点 x'C1C2C3C4' 是 ASCII 字符串'ÁÂÃÄ'

您可能希望在从 IBM 端发送它之前将其转换为 ASCII。 'C1C2C3C4' 会变成 '41424344' 等等。

【讨论】:

  • 实际上,ASCII 甚至没有代码点 C1 到 C4。您可能指的是 Latin-1 或 ISO 8859-1。
  • 积分已授予。我真正想表达的想法是,来回发送“十六进制”不是某种单一的、绝对的、一成不变的字符集。
  • 感谢您的回答,但 EBCDIC -> ASCII 转换确实发生了。我愚蠢地忘记提及这一点。我不确定这是否仍然是一个问题。 For example, say I have a public key in the client that converts to hex as "4F58E1463B66CAAC1BDD35C518A6B76E52E0464E635050B50C87329CFC4C154B8EA07B12AF0E0B9754D5331235805CF59ABE1BB500B4906BD03BCF6C7861E2E8" then I can look at the data in the debugger in the RPG and see the same bytes. (见我编辑的问题)
  • BigInteger 希望字节数组为小端。所以它将 {5,4,3,2,1} 转换为整数 4328719365 IBM i 是大端。如果 API 返回 12345 作为共享密钥,那么 BigInteger 将“返回”转换为 64 字节“整数”时字节顺序错误。是否需要这些转换,因为它不是直接的套接字连接(并且字符串需要转义)?
  • 是否就像在转换为十六进制字符串之前反转客户端密钥的字节数组一样简单,所以 {5,4,3,2,1} 会转到 {1,2,3, 4,5}?然后与服务器密钥相同 - 转换为十六进制然后转换为字节数组并反转?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-05
  • 2021-01-06
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2017-03-17
相关资源
最近更新 更多