英文:
How do I specify a Bouncy Castle public key from a Byte array?
问题
我需要通过I2C接口与微控制器实现密钥交换,密钥以字节形式传输。我正在使用Visual Studio 2022和C#进行开发。由于我需要访问秘密协议(ECDH),所以无法使用Visual Studio加密库,因此我转向了Bouncy Castle。我能够将公钥的两个部分存储为字节数组以发送到微控制器 - 示例代码如下 - 但是我无法弄清楚如何将从微控制器接收到的公钥放入Bouncy Castle的公钥对象中,以便在生成秘密协议时使用。
public void TestBC()
{
String SecretString = "";
int j;
AsymmetricKeyPair<AsymmetricECPublicKey, AsymmetricECPrivateKey> InitiatorKey = GenerateECDHKeyPair();
AsymmetricKeyPair<AsymmetricECPublicKey, AsymmetricECPrivateKey> RecipientKey = GenerateECDHKeyPair();
String RecipPublicKeyX = RecipientKey.PublicKey.W.XCoord.ToString();
String RecipPublicKeyY = RecipientKey.PublicKey.W.YCoord.ToString();
MessageBox.Show(RecipPublicKeyW + "\r\n" + RecipPublicKeyX + "\r\n" + RecipPublicKeyY);
Byte[] SecretAgreement = GetSecretAgreement(InitiatorKey.PrivateKey, RecipientKey.PublicKey);
Byte[] publicX = ConvertHexStringToByteArray(RecipPublicKeyX);
Byte[] publicY = ConvertHexStringToByteArray(RecipPublicKeyY);
for(j=0; j<SecretAgreement.Length; j++)
SecretString += String.Format("{0:X2}",SecretAgreement[j]);
MessageBox.Show(SecretString);
}
public AsymmetricKeyPair<AsymmetricECPublicKey, AsymmetricECPrivateKey> GenerateECDHKeyPair()
{
FipsEC.KeyGenerationParameters KeyGenParameters = new FipsEC.KeyGenerationParameters(FipsEC.DomainParams.P256).For(FipsEC.Cdh);
FipsEC.KeyPairGenerator KpGen = CryptoServicesRegistrar.CreateGenerator(KeyGenParameters, new Org.BouncyCastle.Security.SecureRandom());
return KpGen.GenerateKeyPair();
}
public static byte[] GetSecretAgreement(AsymmetricECPrivateKey InitiatorPrivate, AsymmetricECPublicKey RecipientPublic)
{
IAgreementCalculatorService agreeFact = CryptoServicesRegistrar.CreateService(InitiatorPrivate);
IAgreementCalculator<FipsEC.AgreementParameters> agreement = agreeFact.CreateAgreementCalculator(FipsEC.Cdh);
return agreement.Calculate(RecipientPublic);
}
public static byte[] ConvertHexStringToByteArray(string hexString)
{
if (hexString.Length % 2 != 0)
{
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The hex string cannot have an odd number of digits: {0}", hexString));
}
byte[] data = new byte[hexString.Length / 2];
for (int index = 0; index < data.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
data[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return data;
}
Visual Studio的智能感知不显示AsymmetricECPublicKey对象的任何构造函数、属性或方法,允许我将公钥从字节数组(或字符串)中输入。而且协议计算器似乎需要一个公钥对象。我找到了一些类似的问题已经发布,但它们没有帮助我。有没有人知道如何使用字节数组或字符串来实现这个目标?
英文:
I need to implement key exchange through an I2C interface with a microcontoller, with the keys transferred byte by byte. I am working in Visual Studio 2022, C#. Because I need access to the Secret Agreement (ECDH), I can't use the Visual Studio encryption library, so have turned to Bouncy Castle. I am able to get the two parts of the public key into Byte arrays to send to the micro - example code shown - but have not been able to figure out how to put the public key received from the micro into a Bouncy Castle public key object to use in generating a secret agreement.
public void TestBC()
{
String SecretString = "";
int j;
AsymmetricKeyPair<AsymmetricECPublicKey, AsymmetricECPrivateKey> InitiatorKey = GenerateECDHKeyPair();
AsymmetricKeyPair<AsymmetricECPublicKey, AsymmetricECPrivateKey> RecipientKey = GenerateECDHKeyPair();
String RecipPublicKeyX = RecipientKey.PublicKey.W.XCoord.ToString();
String RecipPublicKeyY = RecipientKey.PublicKey.W.YCoord.ToString();
MessageBox.Show(RecipPublicKeyW + "\r\n" + RecipPublicKeyX + "\r\n" + RecipPublicKeyY);
Byte[] SecretAgreement = GetSecretAgreement(InitiatorKey.PrivateKey, RecipientKey.PublicKey);
Byte[] publicX = ConvertHexStringToByteArray(RecipPublicKeyX);
Byte[] publicY = ConvertHexStringToByteArray(RecipPublicKeyY);
for(j=0; j<SecretAgreement.Length; j++)
SecretString += String.Format("{0:X2}",SecretAgreement[j]);
MessageBox.Show(SecretString);
}
public AsymmetricKeyPair<AsymmetricECPublicKey, AsymmetricECPrivateKey> GenerateECDHKeyPair()
{
FipsEC.KeyGenerationParameters KeyGenParameters = new FipsEC.KeyGenerationParameters(FipsEC.DomainParams.P256).For(FipsEC.Cdh);
FipsEC.KeyPairGenerator KpGen = CryptoServicesRegistrar.CreateGenerator(KeyGenParameters, new Org.BouncyCastle.Security.SecureRandom());
return KpGen.GenerateKeyPair();
}
public static byte[] GetSecretAgreement(AsymmetricECPrivateKey InitiatorPrivate, AsymmetricECPublicKey RecipientPublic)
{
IAgreementCalculatorService agreeFact = CryptoServicesRegistrar.CreateService(InitiatorPrivate);
IAgreementCalculator<FipsEC.AgreementParameters> agreement = agreeFact.CreateAgreementCalculator(FipsEC.Cdh);
return agreement.Calculate(RecipientPublic);
}
public static byte[] ConvertHexStringToByteArray(string hexString)
{
if (hexString.Length % 2 != 0)
{
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The hex string cannot have an odd number of digits: {0}", hexString));
}
byte[] data = new byte[hexString.Length / 2];
for (int index = 0; index < data.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
data[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return data;
}
Visual Studio intellisense does not show any constructors, properties, or methods for the AsymmetricECPublicKey object that will allow me to put in the pbulic key from a Byte array (or string). And the agreement calculator appears to require a public key object. I found a couple of similar questions already posted, but they did not help me. Does anyone know how to use a Byte array or string to do this?
答案1
得分: 0
如果给定公钥的原始 x 和 y 坐标,首先应将其转换为未压缩格式。未压缩格式由以下内容串联而成:一个前导的 0x04 字节,x 坐标和 y 坐标。对于 P-256,x 和 y 坐标都是 32 字节(如果 x 坐标较小,必须从前面用 0x00 填充为 32 字节;对 y 坐标也适用相同的规则):
Byte[] publicX = ...;
Byte[] publicY = ...;
Byte[] uncompressedKey = new byte[1 + 32 + 32]; // 对太短的值进行填充(即小于 32 字节的值),填充到前面用 0x00
uncompressedKey[0] = 0x04;
Buffer.BlockCopy(publicX, 0, uncompressedKey, 1 + (32 - publicX.Length), publicX.Length);
Buffer.BlockCopy(publicY, 0, uncompressedKey, 1 + 32 + (32 - publicY.Length), publicY.Length);
然后,可以按以下方式导入未压缩密钥:
FipsEC.KeyGenerationParameters keyGenParameters = new FipsEC.KeyGenerationParameters(FipsEC.DomainParams.P256).For(FipsEC.Cdh);
AsymmetricECPublicKey publicKey = new AsymmetricECPublicKey(FipsEC.Alg, KeyGenParameters.DomainParameters, KeyGenParameters.DomainParameters.Curve.DecodePoint(uncompressedKey));
为了完整起见:也可以将密钥转换为压缩格式并导入。压缩格式是一个前导的 0x02 字节(如果 y 是偶数)或 0x03 字节(如果 y 是奇数),以及 x 坐标的串联(根据此信息,可以唯一确定公钥,因为可以从此信息重建出 y 坐标)。
英文:
Preliminary note: The question and answer refer to the C#/BouncyCastle FIPS version and not the regular C#/BouncyCastle version.
If the public key is given as raw x and y coordinates, it should first be converted to the uncompressed format. The uncompressed format is given by the concatenation of a leading 0x04 byte, the x coordinate and the y coordinate. The last two are 32 bytes each for P-256 (if the x coordinate is smaller, it must be padded from the front with 0x00 to 32 bytes; the same applies to the y coordinate):
Byte[] publicX = ...;
Byte[] publicY = ...;
Byte[] uncompressedKey = new byte[1 + 32 + 32]; // pad too short values (i.e. values < 32 bytes) with leading 0x00
uncompressedKey[0] = 0x04;
Buffer.BlockCopy(publicX, 0, uncompressedKey, 1 + (32 - publicX.Length), publicX.Length);
Buffer.BlockCopy(publicY, 0, uncompressedKey, 1 + 32 + (32 - publicY.Length), publicY.Length);
The uncompressed key can then be imported as follows:
FipsEC.KeyGenerationParameters keyGenParameters = new FipsEC.KeyGenerationParameters(FipsEC.DomainParams.P256).For(FipsEC.Cdh);
AsymmetricECPublicKey publicKey = new AsymmetricECPublicKey(FipsEC.Alg, KeyGenParameters.DomainParameters, KeyGenParameters.DomainParameters.Curve.DecodePoint(uncompressedKey));
For completeness: It is also possible to convert the key to the compressed format and import it. The compressed format is the concatenation of a leading 0x02 byte (if y is even) or 0x03 byte (if y is odd) and the x coordinate (with this information the public key is uniquely determined, since from this information the y coordinate can be reconstructed).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论