zoukankan      html  css  js  c++  java
  • C#与Java的RSA中的X509EncodedKeySpec、PKCS8EncodedKeySpec

    1、JAVA - RSA使用X509EncodedKeySpec、PKCS8EncodedKeySpec生成公钥和私钥

    	private static final String KEY_ALGORITHM = "RSA";  
    	private static final String PUBLIC_KEY ="publicKey";
    	private static final String PRIVATE_KEY ="privateKey"; 
            public static void main(String[] args) throws Exception{
    		Map<String,String> keyMap = genKey();
    		RSAPublicKey publicKey = getPublicKey(keyMap.get(PUBLIC_KEY));
    		RSAPrivateKey privateKey = getPrivateKey(keyMap.get(PRIVATE_KEY));
    		String info ="明文123456";
    		//加密
    		byte[] bytes = encrypt(info.getBytes("utf-8"),publicKey);
    		//解密
    		bytes = decrypt(bytes, privateKey);
    		System.out.println(new String(bytes,"utf-8"));
    
    	}
    
    	public static Map<String,String> genKey() throws NoSuchAlgorithmException{
    		Map<String,String> keyMap = new HashMap<String,String>();
    		KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
    		SecureRandom random = new SecureRandom();
    		// random.setSeed(keyInfo.getBytes());
    		// 初始加密,512位已被破解,用1024位,最好用2048位
    		keygen.initialize(1024, random);
    		// 取得密钥对
    		KeyPair kp = keygen.generateKeyPair();
    		RSAPrivateKey privateKey = (RSAPrivateKey)kp.getPrivate();
     		String privateKeyString = Base64.encode(privateKey.getEncoded());
    		RSAPublicKey publicKey = (RSAPublicKey)kp.getPublic(); 
    		String publicKeyString = Base64.encode(publicKey.getEncoded());
    		keyMap.put(PUBLIC_KEY, publicKeyString);
    		keyMap.put(PRIVATE_KEY, privateKeyString);
    		return keyMap;
    	}
    
    	public static RSAPublicKey getPublicKey(String publicKey) throws Exception{
    		byte[] keyBytes = LBase64.decode(publicKey);
    		X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
    		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    		return (RSAPublicKey) keyFactory.generatePublic(spec);
    	}
    
    	public static RSAPrivateKey getPrivateKey(String privateKey) throws Exception{
    		byte[] keyBytes = LBase64.decode(privateKey);
    		PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
    		return (RSAPrivateKey) keyFactory.generatePrivate(spec);
    	}
    

    2、C# - RSA使用X509EncodedKeySpec、PKCS8EncodedKeySpec生成公钥和私钥

    /*********** Java代码 ***********/
    //System.out.println(bytes2hex(publicKey.getModulus().toByteArray()));
    //System.out.println(bytes2hex(publicKey.getPublicExponent().toByteArray()));
    
    //设定RSA参数,用于指定modulus和exponent
    var parameter = new RSAParameters();
    parameter.Modulus = modulusBytes;       //modulusBytes是转化后的byte[]
    parameter.Exponent = exponentBytes;
                                                         
    //加密
    var rsa = RSACryptoServiceProvider.Create("RSA");
    rsa.ImportParameters(parameter);
    byte[] result = rsa.EncryptValue(Encoding.UTF8.GetBytes("PASSWORD"));
                                                       
    //把密文转化为HEX形式
    string resultHex = BitConverter.ToString(result).Replace("-", "");
    
    #if 0
    //把3个变量转化为System.Numerics.BigInteger
    var modulus = new BigInteger(modulusBytes);
    var exponent = new BigInteger(exponentBytes);
    var data = new BigInteger(Encoding.UTF8.GetBytes("PASSWORD"));
                                               
    //做ModPow运算得到密文,也是BigInteger
    var result = BigInteger.ModPow(data, exponent, modulus);
                                                
    //把密文BigInteger对应的byte[]转化为HEX形式
    string resultHex = BitConverter.ToString(result.ToByteArray()).Replace("-", "");
    #endif
    
    //把3个变量转化为System.Numerics.BigInteger
    var modulus = new BigInteger(modulusBytes.Reverse().ToArray());
    var exponent = new BigInteger(exponentBytes.Reverse().ToArray());
    var data = new BigInteger(Encoding.UTF8.GetBytes("PASSWORD").Reverse().ToArray());
                                                
    //做ModPow运算得到密文,也是BigInteger
    var result = BigInteger.ModPow(d, e, m);
                                                
    //把密文BigInteger对应的byte[]转化为HEX形式
    string resultHex = BitConverter.ToString(result.ToByteArray().Reverse().ToArray()).Replace("-", "");
    

    3、C# - JAVA - RSA使用X509EncodedKeySpec、PKCS8EncodedKeySpec生成公钥和私钥解析

      1. Java程序员很少想过getEncoded()是什么算法,它是如何把modulus与publicExponent封装到一个byte[]里去的。

      2. 而对于C#程序员来讲,RSA公钥加密必须要用到modulus与publicExponent,无论它们是XML形式还是byte[]形式,因此如何从publicKeyHex中解析这两个参数就成了第一个关键点。

      3. JavaDoc:

    An Encoded Form
    
    This is an external encoded form for the key used when a standard representation of the key is needed outside
    the Java Virtual Machine, as when transmitting the key to some other party. The key is encoded according to
    a standard format (such as X.509 SubjectPublicKeyInfo or PKCS#8), and is returned using the getEncoded method.
    Note: The syntax of the ASN.1 type SubjectPublicKeyInfo is defined as follows:
    
    SubjectPublicKeyInfo ::= SEQUENCE {
      algorithm AlgorithmIdentifier,
      subjectPublicKey BIT STRING 
    }
    
    AlgorithmIdentifier ::= SEQUENCE {
      algorithm OBJECT IDENTIFIER,
      parameters ANY DEFINED BY algorithm OPTIONAL 
    }
    
    For more information, see RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile.
    

    根据ASN.1标准进行保存的,涉及到了2种格式:X.509 SubjectPublicKeyInfo和PKCS#8, 具体是哪种可以从getFormat()的方法说明里可以找到答案:公钥使用的是X.509 SubjectPublicKeyInfo,私钥使用的是PKCS#8。 

    JavaDoc里已经描述了SubjectPublicKeyInfo的结构如下:

    SEQUENCE {
        SEQUENCE {          //algorithm,我们不用关心具体结构
        }
        BIT STRING {        //SubjectPublicKey,以BIT STRING存储
            SEQUENCE {
                INTEGER     //modulus
                INTEGER     //publicExponent
            }
        }
    }
    

    Java端使用的是2048位的标准RSA加密,给出的公钥HEX字符串如下:

    30820122300D06092A864886F70D01010105000382010F003082010A02820101008C214751E6EA33378080F64BF55C0888D3EFA4DF08794318069DDFD14A3AB6468B20CD134819100FA20539785AECF595CF2333F7ADC48366F4ACBC41B1CED728B57417CF3B6CA4E7DDB9DA348F7D38158DD6F2FF3934AEB0A70732E2949505EF893A940404B1B5F4B69243E2877BBA90E5994EBFD61986F412DE4AD3E8331CE1D3D41ADAEF5C79D5B22E05C7F76FC748BC5FA42345D70EC3D1DE3DBD338C300C3750841E2E16E7B907E536FCA1A40D05DC9DFCDE4EB2E8575228309AD146486E6F21C386E90C36DEECB57F955CE68609204AFBD434F8A1BFB5D921C470EED82CCA8BFDA92A8EC668E9E9EB6F959CD535C8BCCFCB08A671983A27E8B03F5BF90D0203010001
    

    对照着ASN.1规范,格式如下:

      二进制          解析
    --------------------------------------------------------------
    30  0011 0000       TAG:类型00=通用,1=结构体,10000=16=SEQUENCE
    82  1000 0010       LEN:定长,长形式,后面2字节是长度
    01                     长度 0x122=290字节,注意是大字节序
    22
    30  0011 0000       TAG:类型00=通用,1=结构体,10000=16=SEQUENCE
    0D  0000 1101       LEN:定长,短形式,13字节
    06                  VAL:13字节,我们不关心内容,跳过
    09
    .
    .
    .
    05
    00
    03  0000 0011       TAG:类型00=通用类型,0=简单数据,00011=3=BIT STRING
    82  1000 0010       LEN:定长,长形式,后面2字节是长度,注意是大字节序
    01                     长度 0x10f=271字节
    0F
    00                  保留字
    30  0011 0000       TAG:类型00=通用类型,1=结构体,10000=16=SEQUENCE
    82  1000 0010       LEN:定长,长形式,后面2字节是长度,注意是大字节序
    01                     长度 0x10a=266字节
    0A
    02  0000 0010       TAG:类型00,0=简单数据,00010=2=INTEGER
    82  1000 0010       LEN:定长,长形式,后面2字节是长度,注意是大字节序
    01                      长度=0x101,257字节
    01
    00                  VAL:257字节,是公钥中的modulus
    8C
    .
    .
    .
    F9
    0D
    02  0000 0010       TAG:类型00,0=简单数据,00010=2=INTEGER
    03  0000 0011       LEN:定长,短形式,3字节
    01 00 01            VAL:3字节,是公钥中的publicExponent
    再度整理后:
    类型  长度位  实际长度
    -----------------------------------------------
    30    82     01 22     SEQUENCE {
    30    0D     0D            SEQUENCE {
                               }
    03    82     01 0F         BIT STRING {
    30    82     01 0A             SEQUENCE {
    02    82     01 01                 INTEGER
                                           00 8C 21 47 51 E6 EA 33 37 80 80 F6 4B F5 5C 08
                                           88 D3 EF A4 DF 08 79 43 18 06 9D DF D1 4A 3A B6
                                           .......
                                           35 C8 BC CF CB 08 A6 71 98 3A 27 E8 B0 3F 5B F9
                                           0D
    02    03     03                    INTEGER
                                           01 00 01
                                   }
                               }
                           }
    

      

  • 相关阅读:
    springboot2 整合雪花算法,并兼容分布式部署
    docker 在 linux 搭建私有仓库
    jdbc 几种关系型数据库的连接 和 driver_class,以及简单的使用
    springboot2 整合发送邮件的功能
    oracle 唯一新约束 和 逻辑删除的 冲突处理办法
    oracle 一些常见操作方法
    spring-cloud-stream 整合 rabbitmq
    springboot2 整合 rabbitmq
    docker 安装 rabbitmq 消息队列
    网络统计学目录
  • 原文地址:https://www.cnblogs.com/desultory-essay/p/13501738.html
Copyright © 2011-2022 走看看