zoukankan      html  css  js  c++  java
  • RSADemo1

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading.Tasks;

    namespace ERN.Tools.Common
    {
    /// <summary>
    /// RSA PEM格式秘钥对的解析和导出
    /// </summary>
    public class RSA_PEM
    {
    /// <summary>
    /// 用PEM格式密钥对创建RSA,支持PKCS#1、PKCS#8格式的PEM
    /// </summary>
    public static RSACryptoServiceProvider FromPEM(string pem)
    {
    var rsaParams = new CspParameters();
    rsaParams.Flags = CspProviderFlags.UseMachineKeyStore;
    var rsa = new RSACryptoServiceProvider(rsaParams);

    var param = new RSAParameters();

    var base64 = _PEMCode.Replace(pem, "");
    var data = RSA_Unit.Base64DecodeBytes(base64);
    if (data == null)
    {
    throw new Exception("PEM内容无效");
    }
    var idx = 0;

    //读取长度
    Func<byte, int> readLen = (first) => {
    if (data[idx] == first)
    {
    idx++;
    if (data[idx] == 0x81)
    {
    idx++;
    return data[idx++];
    }
    else if (data[idx] == 0x82)
    {
    idx++;
    return (((int)data[idx++]) << 8) + data[idx++];
    }
    else if (data[idx] < 0x80)
    {
    return data[idx++];
    }
    }
    throw new Exception("PEM未能提取到数据");
    };
    //读取块数据
    Func<byte[]> readBlock = () => {
    var len = readLen(0x02);
    if (data[idx] == 0x00)
    {
    idx++;
    len--;
    }
    var val = data.sub(idx, len);
    idx += len;
    return val;
    };
    //比较data从idx位置开始是否是byts内容
    Func<byte[], bool> eq = (byts) => {
    for (var i = 0; i < byts.Length; i++, idx++)
    {
    if (idx >= data.Length)
    {
    return false;
    }
    if (byts[i] != data[idx])
    {
    return false;
    }
    }
    return true;
    };


    if (pem.Contains("PUBLIC KEY"))
    {
    /****使用公钥****/
    //读取数据总长度
    readLen(0x30);
    if (!eq(_SeqOID))
    {
    throw new Exception("PEM未知格式");
    }
    //读取1长度
    readLen(0x03);
    idx++;//跳过0x00
    //读取2长度
    readLen(0x30);

    //Modulus
    param.Modulus = readBlock();

    //Exponent
    param.Exponent = readBlock();
    }
    else if (pem.Contains("PRIVATE KEY"))
    {
    /****使用私钥****/
    //读取数据总长度
    readLen(0x30);

    //读取版本号
    if (!eq(_Ver))
    {
    throw new Exception("PEM未知版本");
    }

    //检测PKCS8
    var idx2 = idx;
    if (eq(_SeqOID))
    {
    //读取1长度
    readLen(0x04);
    //读取2长度
    readLen(0x30);

    //读取版本号
    if (!eq(_Ver))
    {
    throw new Exception("PEM版本无效");
    }
    }
    else
    {
    idx = idx2;
    }

    //读取数据
    param.Modulus = readBlock();
    param.Exponent = readBlock();
    param.D = readBlock();
    param.P = readBlock();
    param.Q = readBlock();
    param.DP = readBlock();
    param.DQ = readBlock();
    param.InverseQ = readBlock();
    }
    else
    {
    throw new Exception("pem需要BEGIN END标头");
    }

    rsa.ImportParameters(param);
    return rsa;
    }
    static private Regex _PEMCode = new Regex(@"--+.+?--+|s+");
    static private byte[] _SeqOID = new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
    static private byte[] _Ver = new byte[] { 0x02, 0x01, 0x00 };

    /// <summary>
    /// XML格式转PEM
    /// </summary>
    /// <param name="key">原始XML字符</param>
    /// <param name="convertToPublic">true=公钥 false=私钥</param>
    /// <param name="usePKCS8">usePKCS8=false时返回PKCS#1格式,否则返回PKCS#8格式</param>
    /// <returns></returns>
    public static string ToPEM(string key, bool convertToPublic, bool usePKCS8 = false)
    {
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    rsa.FromXmlString(key);
    return ToPEM(rsa, convertToPublic, usePKCS8);
    }


    /// <summary>
    /// 将RSA中的密钥对转换成PEM格式,usePKCS8=false时返回PKCS#1格式,否则返回PKCS#8格式,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响
    /// </summary>
    public static string ToPEM(RSACryptoServiceProvider rsa, bool convertToPublic, bool usePKCS8)
    {
    //https://www.jianshu.com/p/25803dd9527d
    //https://www.cnblogs.com/ylz8401/p/8443819.html
    //https://blog.csdn.net/jiayanhui2877/article/details/47187077
    //https://blog.csdn.net/xuanshao_/article/details/51679824
    //https://blog.csdn.net/xuanshao_/article/details/51672547

    var ms = new MemoryStream();
    //写入一个长度字节码
    Action<int> writeLenByte = (len) => {
    if (len < 0x80)
    {
    ms.WriteByte((byte)len);
    }
    else if (len <= 0xff)
    {
    ms.WriteByte(0x81);
    ms.WriteByte((byte)len);
    }
    else
    {
    ms.WriteByte(0x82);
    ms.WriteByte((byte)(len >> 8 & 0xff));
    ms.WriteByte((byte)(len & 0xff));
    }
    };
    //写入一块数据
    Action<byte[]> writeBlock = (byts) => {
    var addZero = (byts[0] >> 4) >= 0x8;
    ms.WriteByte(0x02);
    var len = byts.Length + (addZero ? 1 : 0);
    writeLenByte(len);

    if (addZero)
    {
    ms.WriteByte(0x00);
    }
    ms.Write(byts, 0, byts.Length);
    };
    //根据后续内容长度写入长度数据
    Func<int, byte[], byte[]> writeLen = (index, byts) => {
    var len = byts.Length - index;

    ms.SetLength(0);
    ms.Write(byts, 0, index);
    writeLenByte(len);
    ms.Write(byts, index, len);

    return ms.ToArray();
    };


    if (rsa.PublicOnly || convertToPublic)
    {
    /****生成公钥****/
    var param = rsa.ExportParameters(false);


    //写入总字节数,不含本段长度,额外需要24字节的头,后续计算好填入
    ms.WriteByte(0x30);
    var index1 = (int)ms.Length;

    //固定内容
    // encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
    ms.writeAll(_SeqOID);

    //从0x00开始的后续长度
    ms.WriteByte(0x03);
    var index2 = (int)ms.Length;
    ms.WriteByte(0x00);

    //后续内容长度
    ms.WriteByte(0x30);
    var index3 = (int)ms.Length;

    //写入Modulus
    writeBlock(param.Modulus);

    //写入Exponent
    writeBlock(param.Exponent);


    //计算空缺的长度
    var byts = ms.ToArray();

    byts = writeLen(index3, byts);
    byts = writeLen(index2, byts);
    byts = writeLen(index1, byts);


    return "-----BEGIN PUBLIC KEY----- " + RSA_Unit.TextBreak(RSA_Unit.Base64EncodeBytes(byts), 64) + " -----END PUBLIC KEY-----";
    }
    else
    {
    /****生成私钥****/
    var param = rsa.ExportParameters(true);

    //写入总字节数,后续写入
    ms.WriteByte(0x30);
    int index1 = (int)ms.Length;

    //写入版本号
    ms.writeAll(_Ver);

    //PKCS8 多一段数据
    int index2 = -1, index3 = -1;
    if (usePKCS8)
    {
    //固定内容
    ms.writeAll(_SeqOID);

    //后续内容长度
    ms.WriteByte(0x04);
    index2 = (int)ms.Length;

    //后续内容长度
    ms.WriteByte(0x30);
    index3 = (int)ms.Length;

    //写入版本号
    ms.writeAll(_Ver);
    }

    //写入数据
    writeBlock(param.Modulus);
    writeBlock(param.Exponent);
    writeBlock(param.D);
    writeBlock(param.P);
    writeBlock(param.Q);
    writeBlock(param.DP);
    writeBlock(param.DQ);
    writeBlock(param.InverseQ);


    //计算空缺的长度
    var byts = ms.ToArray();

    if (index2 != -1)
    {
    byts = writeLen(index3, byts);
    byts = writeLen(index2, byts);
    }
    byts = writeLen(index1, byts);


    var flag = " PRIVATE KEY";
    if (!usePKCS8)
    {
    flag = " RSA" + flag;
    }
    return "-----BEGIN" + flag + "----- " + RSA_Unit.TextBreak(RSA_Unit.Base64EncodeBytes(byts), 64) + " -----END" + flag + "-----";
    }
    }
    }
    }

  • 相关阅读:
    PAT 1123 Is It a Complete AVL Tree
    PAT 1122 Hamiltonian Cycle
    PAT 1121 Damn Single
    PAT 1120 Friend Numbers
    JS数组的sort排序
    [转] jquery操作select(取值,设置选中)
    [转]2013和2014年中国互联网企业100强排行榜
    css 更换浏览器 默认图标
    [转]CSS禁止文字选择
    github 在线 创建文件夹
  • 原文地址:https://www.cnblogs.com/lockzy/p/11759029.html
Copyright © 2011-2022 走看看