Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何调整C#的公共/私有RSA密钥,以便像在Java中一样使用它们?_Java_C#_Cryptography_Rsa - Fatal编程技术网

如何调整C#的公共/私有RSA密钥,以便像在Java中一样使用它们?

如何调整C#的公共/私有RSA密钥,以便像在Java中一样使用它们?,java,c#,cryptography,rsa,Java,C#,Cryptography,Rsa,我有一些通过加密API访问数据的服务器。我需要用C语言编写客户端,它可以创建对服务器的请求并从服务器读取响应 为此,我需要创建公共和私有RSA密钥,并将它们转换为字节数组。我有一个java的工作示例: java.security.KeyPairjava.security.KeyPair keypair = keyGen.genKeyPair(); byte[] pubKeyBytes = keypair.getPublic().getEncoded(); byte[]

我有一些通过加密API访问数据的服务器。我需要用C语言编写客户端,它可以创建对服务器的请求并从服务器读取响应

为此,我需要创建公共和私有RSA密钥,并将它们转换为字节数组。我有一个java的工作示例:

    java.security.KeyPairjava.security.KeyPair keypair = keyGen.genKeyPair();

    byte[] pubKeyBytes = keypair.getPublic().getEncoded();
    byte[] privKeyBytes = keypair.getPrivate().getEncoded();
我试着在.NET中使用C#做同样的事情:

我不知道怎么做。我将D、Dp、DQ、InverseQ、模、指数作为公钥和私钥的属性,但在java示例中,这些键看起来像单个联合键。我应该在任务中使用哪一个D、Dp、DQ、InverseQ、模数、指数?什么方法与java示例中的方法相同,但在C#?

中,您需要使用以下方法:

ExportParameters
导出特定参数,从中可以计算密钥本身。有关这些参数的更多信息,请参见。

,根据公钥编码的默认值是X.509 SubjectPublicKeyInfo,私钥的默认值是PKCS#8 PrivateKeyInfo

关于从SubjectPublicKeyInfo创建参数,有很多问题(如),但相反的问题就没有那么多了

如果您通过RSACryptServiceProvider创建密钥,则新密钥的指数值始终为0x010001,这意味着您必须处理的唯一可变大小的数据块是模数值。这一点很重要的原因是SubjectPublicKeyInfo(几乎总是)以DER(由定义)编码,DER使用长度前缀值。ASN.1()在as中定义

RSA算法标识符的编码值为

30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00
(aka序列(,NULL))

subjectPublicKey
的值取决于算法。对于RSA,它是
RSAPublicKey
,在中定义为

整数的编码是02(然后是长度),然后是有符号的大端值。因此,假设您的指数值为
01 00 01
,则编码值为
02 03 01 00 01
。模数长度取决于钥匙的大小

int modulusBytes = parameters.Modulus.Length;

if (parameters.Modulus[0] >= 0x80)
    modulusBytes++;
RSACryptServiceProvider应始终创建需要额外字节的密钥,但从技术上讲,可能存在不需要额外字节的密钥。我们需要它的原因是parameters.module是一种无符号的big-endian编码,如果设置了高位,那么我们将在RSAPublicKey中编码一个负数。我们通过插入一个00字节来修复这个问题,以保持符号位清晰

模数的长度字节有点棘手。如果模数可以表示为127字节或更少(RSA-1015或更小),则只需使用一个字节作为该值。否则,您需要最小的字节数来报告该数字,再加上一个。这个额外的字节(实际上是第一个)表示长度是多少字节。所以128-255是一个字节,
81
。256-65535是两个,所以
82

然后我们需要将其包装成一个位字符串值,这很容易(如果我们忽略硬部分,因为它们在这里不相关)。然后把其他的东西按顺序包起来,这很容易

快速且脏,仅适用于指数为0x010001的2048位键:

private static byte[] s_prefix =
{
    0x30, 0x82, 0x01, 0x22,
          0x30, 0x0D,
                0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
                0x05, 0x00,
          0x03, 0x82, 0x01, 0x0F,
                0x00,
                0x30, 0x82, 0x01, 0x0A,
                      0x02, 0x82, 0x01, 0x01, 0x00
};

private static byte[] s_suffix = { 0x02, 0x03, 0x01, 0x00, 0x01 };

private static byte[] MakeSubjectPublicInfoEasy2048(RSA rsa)
{
    if (rsa.KeySize != 2048)
        throw new ArgumentException(nameof(rsa));

    RSAParameters rsaParameters = rsa.ExportParameters(false);

    if (Convert.ToBase64String(rsaParameters.Exponent) != "AQAB")
    {
        throw new ArgumentException(nameof(rsa));
    }

    return s_prefix.Concat(rsaParameters.Modulus).Concat(s_suffix).ToArray();
}
或者,对于通用响应(创建大量临时字节[]s):

它还表示当前版本号为0

私钥的八位字节字符串由算法定义。对于RSA,我们可以在RFC 3447中看到,以及
RSAPublicKey

RSAPrivateKey ::= SEQUENCE {
  version           Version,
  modulus           INTEGER,  -- n
  publicExponent    INTEGER,  -- e
  privateExponent   INTEGER,  -- d
  prime1            INTEGER,  -- p
  prime2            INTEGER,  -- q
  exponent1         INTEGER,  -- d mod (p-1)
  exponent2         INTEGER,  -- d mod (q-1)
  coefficient       INTEGER,  -- (inverse of q) mod p
  otherPrimeInfos   OtherPrimeInfos OPTIONAL }
忽略
otherPrimeInfos
。它不适用,也永远不应该适用。因此,要使用的版本号为0

使用已经定义的实用方法,我们通过

private static byte[] MakeOctetString(byte[] data)
{
    return MakeTagLengthValue(0x04, data);
}

private static byte[] s_integerZero = new byte[] { 0x02, 0x01, 0x00 };

private static byte[] ExportPrivateKeyInfo(RSA rsa)
{
    RSAParameters parameters = rsa.ExportParameters(true);

    return MakeSequence(
        s_integerZero,
        s_rsaAlgorithmId,
        MakeOctetString(
            MakeSequence(
                s_integerZero,
                MakeInteger(parameters.Modulus),
                MakeInteger(parameters.Exponent),
                MakeInteger(parameters.D),
                MakeInteger(parameters.P),
                MakeInteger(parameters.Q),
                MakeInteger(parameters.DP),
                MakeInteger(parameters.DQ),
                MakeInteger(parameters.InverseQ))));
}
在.NET Core的功能路线图上(没有说导出,但有导入的地方通常有导出:)可以使所有这些变得更容易


将您的输出保存到一个文件中,您可以使用
openssl rsa-inform der-pubin-text-in pub.key
openssl rsa-inform der-text-in priv.key

检查它,它们看起来正是我需要的。但是我会实现我的客户端来检查它是否工作,然后接受你的答案。我检查了,结果不一样。你需要如何处理字节?将它们发送到Windows上的另一个C#程序?将它们发送到Java?只需将它们保存并加载到同一台计算机上,即可创建对第三方服务的加密请求。此服务提供了一个描述如何执行此操作的算法。该算法在49页的文档中进行了描述。实现此算法需要以字节为单位的键。
ExportCspBlob
可能不是您想要的答案。您可能需要查找SubjectPublicKeyInfo和PKCS8。(或者,如果仅是RSA,则可能只是RSAPublicKey和RSAPrivateKey)。如果没有更好的答案时,我有一个电话以外的其他东西可用,我会尝试更好的东西比这个提示:)我需要发送公钥(加密的hmac密码,这是已知的只有我作为一个客户端的这项服务)在头的http请求。响应由来自报头的公钥加密,我需要解密它。我知道keypair.getPublic().getEncoded()在这个算法中工作正常,但它是java而不是c#。如果我使用根据您的示例计算的公钥,我可以用密钥解密响应吗?@MiraiMann我不明白。HMAC不是一种加密算法。但是
ExportSubjectPublicKeyInfo
getPublic().getEncoded()
相同,
ExportPrivateKeyInfo()
getPrivate().getEncoded()
相同。客户端发送该密钥的RSA密钥和HMAC。服务器计算接收到的密钥的HMAC,并将其与接收到的HMAC进行比较以进行验证。无论如何,这是不必要的信息。对不起。明天我会在办公室尝试使用你的解决方案。谢谢。我使用了您示例中的代码,生成的公钥已经过验证。结果,我对响应进行了加密,并尝试使用私钥对其进行解密,但未成功。我使用rsa.Decrypt(src,tru
int modulusBytes = parameters.Modulus.Length;

if (parameters.Modulus[0] >= 0x80)
    modulusBytes++;
private static byte[] s_prefix =
{
    0x30, 0x82, 0x01, 0x22,
          0x30, 0x0D,
                0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
                0x05, 0x00,
          0x03, 0x82, 0x01, 0x0F,
                0x00,
                0x30, 0x82, 0x01, 0x0A,
                      0x02, 0x82, 0x01, 0x01, 0x00
};

private static byte[] s_suffix = { 0x02, 0x03, 0x01, 0x00, 0x01 };

private static byte[] MakeSubjectPublicInfoEasy2048(RSA rsa)
{
    if (rsa.KeySize != 2048)
        throw new ArgumentException(nameof(rsa));

    RSAParameters rsaParameters = rsa.ExportParameters(false);

    if (Convert.ToBase64String(rsaParameters.Exponent) != "AQAB")
    {
        throw new ArgumentException(nameof(rsa));
    }

    return s_prefix.Concat(rsaParameters.Modulus).Concat(s_suffix).ToArray();
}
private static byte[] MakeTagLengthValue(byte tag, byte[] value, int index = 0, int length = -1)
{
    if (length == -1)
    {
        length = value.Length - index;
    }

    byte[] data;

    if (length < 0x80)
    {
        data = new byte[length + 2];
        data[1] = (byte)length;
    }
    else if (length <= 0xFF)
    {
        data = new byte[length + 3];
        data[1] = 0x81;
        data[2] = (byte)length;
    }
    else if (length <= 0xFFFF)
    {
        data = new byte[length + 4];
        data[1] = 0x82;
        data[2] = (byte)(length >> 8);
        data[3] = unchecked((byte)length);
    }
    else
    {
        throw new InvalidOperationException("Continue the pattern");
    }

    data[0] = tag;
    int dataOffset = data.Length - length;
    Buffer.BlockCopy(value, index, data, dataOffset, length);
    return data;
}

private static byte[] MakeInteger(byte[] unsignedBigEndianValue)
{
    if (unsignedBigEndianValue[0] >= 0x80)
    {
        byte[] tmp = new byte[unsignedBigEndianValue.Length + 1];
        Buffer.BlockCopy(unsignedBigEndianValue, 0, tmp, 1, unsignedBigEndianValue.Length);
        return MakeTagLengthValue(0x02, tmp);
    }

    for (int i = 0; i < unsignedBigEndianValue.Length; i++)
    {
        if (unsignedBigEndianValue[i] != 0)
        {
            if (unsignedBigEndianValue[i] >= 0x80)
            {
                i--;
            }

            return MakeTagLengthValue(0x02, unsignedBigEndianValue, i);
        }
    }

    // All bytes were 0, encode 0.
    return MakeTagLengthValue(0x02, unsignedBigEndianValue, 0, 1);
}

private static byte[] MakeSequence(params byte[][] data)
{
    return MakeTagLengthValue(0x30, data.SelectMany(a => a).ToArray());
}

private static byte[] MakeBitString(byte[] data)
{
    byte[] tmp = new byte[data.Length + 1];
    // Insert a 0x00 byte for the unused bit count value
    Buffer.BlockCopy(data, 0, tmp, 1, data.Length);
    return MakeTagLengthValue(0x03, tmp);
}

private static byte[] s_rsaAlgorithmId = new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };

private static byte[] ExportSubjectPublicKeyInfo(RSA rsa)
{
    RSAParameters parameters = rsa.ExportParameters(false);

    return MakeSequence(
        s_rsaAlgorithmId,
        MakeBitString(
            MakeSequence(
                MakeInteger(parameters.Modulus),
                MakeInteger(parameters.Exponent))));
}
PrivateKeyInfo ::= SEQUENCE {
  version                   Version,
  privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
  privateKey                PrivateKey,
  attributes           [0]  IMPLICIT Attributes OPTIONAL }

Version ::= INTEGER

PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier

PrivateKey ::= OCTET STRING

Attributes ::= SET OF Attribute
RSAPrivateKey ::= SEQUENCE {
  version           Version,
  modulus           INTEGER,  -- n
  publicExponent    INTEGER,  -- e
  privateExponent   INTEGER,  -- d
  prime1            INTEGER,  -- p
  prime2            INTEGER,  -- q
  exponent1         INTEGER,  -- d mod (p-1)
  exponent2         INTEGER,  -- d mod (q-1)
  coefficient       INTEGER,  -- (inverse of q) mod p
  otherPrimeInfos   OtherPrimeInfos OPTIONAL }
private static byte[] MakeOctetString(byte[] data)
{
    return MakeTagLengthValue(0x04, data);
}

private static byte[] s_integerZero = new byte[] { 0x02, 0x01, 0x00 };

private static byte[] ExportPrivateKeyInfo(RSA rsa)
{
    RSAParameters parameters = rsa.ExportParameters(true);

    return MakeSequence(
        s_integerZero,
        s_rsaAlgorithmId,
        MakeOctetString(
            MakeSequence(
                s_integerZero,
                MakeInteger(parameters.Modulus),
                MakeInteger(parameters.Exponent),
                MakeInteger(parameters.D),
                MakeInteger(parameters.P),
                MakeInteger(parameters.Q),
                MakeInteger(parameters.DP),
                MakeInteger(parameters.DQ),
                MakeInteger(parameters.InverseQ))));
}