<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Heck's  Blog]]></title> 
<link>https://www.heckjj.com/index.php</link> 
<description><![CDATA[一瞬间的决定，往往可以改变很多，事实上，让自己成功的往往不是知识，是精神！ 如果你总是为自己找借口，那只好让成功推迟。执行力，今天！]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Heck's  Blog]]></copyright>
<item>
<link>https://www.heckjj.com/post/652/</link>
<title><![CDATA[国密算法 SM2 SM3 SM4 密钥生成]]></title> 
<author>Heck &lt;@hecks.tk&gt;</author>
<category><![CDATA[加密破解]]></category>
<pubDate>Mon, 24 Jul 2023 03:13:35 +0000</pubDate> 
<guid>https://www.heckjj.com/post/652/</guid> 
<description>
<![CDATA[ 
	方式一：SM2密钥在线生成<br/>SM2密钥在线生成工具<br/><br/>如果你没线下生成工具，可用下面2种线上生成方式之一：<br/><br/>1. sm2密钥在线生成（<a href="https://const.net.cn/tool/sm2/genkey/" target="_blank">const.net.cn</a>）<br/><br/>2. web encrypt（<a href="https://webencrypt.org/sm2samplecryptjs/" target="_blank">webencrypt.org</a>）<br/><br/>方式一：生成SM2公私钥（.pem格式）<br/>一．系统环境<br/>系统环境：windows系统。<br/>二．工具软件<br/>工具软件：Win64OpenSSL。<br/>三．生成SM2公私钥<br/>步骤一：在windows操作系统上安装Win64OpenSSL软件；<br/>步骤二：打开Win64OpenSSL软件，首先生成私钥，命令为：ecparam -genkey -name SM2 -out priv.key；
]]>
</description>
</item><item>
<link>https://www.heckjj.com/post/526/</link>
<title><![CDATA[java关于RSA公钥/私钥/签名工具包RSAUtils实现密钥对生成、数字签名生成校验等]]></title> 
<author>Heck &lt;@hecks.tk&gt;</author>
<category><![CDATA[加密破解]]></category>
<pubDate>Mon, 23 Nov 2020 06:17:42 +0000</pubDate> 
<guid>https://www.heckjj.com/post/526/</guid> 
<description>
<![CDATA[ 
	对称加密：<br/>DES，AES，加密解密都用一个秘钥，速度快<br/><br/>非对称机密<br/>RSA，可以私钥加密公钥解密，也可以公钥机密私钥解密，速度慢<br/><br/>注意：<br/>RSA加密明文最大长度117字节，解密要求密文最大长度为128字节，所以在加密和解密的过程中需要分块进行。<br/>RSA加密对明文的长度是有限制的，如果加密数据过大会抛出异常：<br/> <br/>常见加密算法<br/><br/>DES <br/>&nbsp;&nbsp;&nbsp;&nbsp;DES是Data Encryption Standard（数据加密标准）的缩写，DES算法为密码体制中的对称密码体制。它是由IBM公司研制的一种加密算法，美国国家标准局于1977年公布把它作为非机要部门使用的数据加密标准，二十年来，它一直活跃在国际保密通信的舞台上，扮演了十分重要的角色。<br/>&nbsp;&nbsp;&nbsp;&nbsp;DES是一个分组加密算法，他以64位为分组对数据加密。同时DES也是一个对称算法：加密和解密用的是同一个算法。它的密匙长度是56位（因为每个第8位都用作奇偶校验），密匙可以是任意的56位的数，而且可以任意时候改变。其中有极少量的数被认为是弱密匙，但是很容易避开他们。所以保密性依赖于密钥。<br/>&nbsp;&nbsp;&nbsp;&nbsp;特点：分组比较短、密钥太短、密码生命周期短、运算速度较慢。<br/>　　DES算法具有极高安全性，到目前为止，除了用穷举搜索法对DES算法进行攻击外，还没有发现更有效的办法。而56位长的密钥的穷举空间为256，这意味着如果一台计算机的速度是每一秒种检测一百万个密钥，则它搜索完全部密钥就需要将近2285年的时间。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;DES现在已经不视为一种安全的加密算法，因为它使用的56位秘钥过短，以现代计算能力，24小时内即可能被破解。也有一些分析报告提出了该算法的理论上的弱点，虽然实际情况未必出现。该标准在最近已经被高级加密标准（AES）所取代。<br/> <br/>AES<br/>&nbsp;&nbsp;&nbsp;&nbsp;高级加密标准（Advanced Encryption Standard，AES），又称Rijndael加密法，是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES，已经被多方分析且广为全世界所使用。经过五年的甄选流程，高级加密标准由美国国家标准与技术研究院（NIST）于2001年11月26日发布于FIPS PUB 197，并在2002年5月26日成为有效的标准。2006年，高级加密标准已然成为对称密钥加密中最流行的算法之一。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;AES的区块长度固定为128 位元，密钥长度则可以是128，192或256位元。<br/><br/>RSA<br/>&nbsp;&nbsp;&nbsp;&nbsp;RSA加密算法是一种非对称加密算法。在公钥加密标准和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特（Ron Rivest）、阿迪·萨莫尔（Adi Shamir）和伦纳德·阿德曼（Leonard Adleman）一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;RSA算法的可靠性基于分解极大的整数是很困难的。假如有人找到一种很快的分解因子的算法的话，那么用RSA加密的信息的可靠性就肯定会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA钥匙才可能被强力方式解破。到2008年为止，世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长，用RSA加密的信息实际上是不能被解破的。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;RSA算法利用两个很大的质数相乘所产生的乘积来加密。这两个质数无论哪一个先与原文件编码相乘，对文件加密，均可由另一个质数再相乘来解密。但要用一个质数来求出另一个质数，则是十分困难的。因此将这一对质数称为密钥对(Key Pair)。在加密应用时，某个用户总是将一个密钥公开，让需发信的人员将信息用其公共密钥加密后发给该用户，而一旦信息加密后，只有用该用户一个人知道的私用密钥才能解密。具有数字凭证身份的人员的公共密钥可在网上查到，亦可在请对方发信息时主动将公共密钥传给对方，这样保证在Internet上传输信息的保密和安全。<br/><br/>关于RSA公钥/私钥/签名RSAUtils工具包类,提供生成密钥对(公钥和私钥)-genKeyPair、用私钥对信息生成数字签名（sign）、校验数字签名（verify）、私钥解密（decryptByPrivateKey）、公钥解密（decryptByPublicKey）、公钥加密（encryptByPublicKey）、私钥加密（encryptByPrivateKey）、获取私钥（getPrivateKey）、获取公钥（getPublicKey）、获取校验码（getVerifyCode）等方法，详情参见代码示例部分。<br/><br/>RSAUtils.java<br/><textarea name="code" class="java" rows="15" cols="100">
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
 
import javax.crypto.Cipher;
 
/** 
* <p>
* RSA公钥/私钥/签名工具包
* </p> 
* <p>
* 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式

* 由于非对称加密速度极其缓慢，一般文件不使用它来加密而是使用对称加密，

* 非对称加密算法可以用来对对称加密的密钥加密，这样保证密钥的安全也就保证了数据的安全
* </p> 
*/
public class RSAUtils &#123;
 
&nbsp;&nbsp; /** 
&nbsp;&nbsp; * 算法供应商
&nbsp;&nbsp; */
&nbsp;&nbsp; public static final String ALG_PROVIDER = "mockAlgorithm";
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * 加密算法RSA
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static final String KEY_ALGORITHM = "RSA";
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * 01-身份证
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static final String ID_CARD= "01";
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * 签名算法
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * 获取公钥的key
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;private static final String PUBLIC_KEY = "RSAPublicKey";
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * 获取私钥的key
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;private static final String PRIVATE_KEY = "RSAPrivateKey";
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;private static final int KEY_SIZE = 2048;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * RSA最大加密明文大小
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;private static final int MAX_ENCRYPT_BLOCK = KEY_SIZE / 8 - 11;
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * RSA最大解密密文大小
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / 8;
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <p>
&nbsp;&nbsp;&nbsp;&nbsp; * 生成密钥对(公钥和私钥)
&nbsp;&nbsp;&nbsp;&nbsp; * </p>
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static Map<String, Object> genKeyPair() throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyPairGen.initialize(KEY_SIZE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyPair keyPair = keyPairGen.generateKeyPair();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map<String, Object> keyMap = new HashMap<String, Object>(2);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyMap.put(PUBLIC_KEY, publicKey);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyMap.put(PRIVATE_KEY, privateKey);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return keyMap;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <p>
&nbsp;&nbsp;&nbsp;&nbsp; * 用私钥对信息生成数字签名
&nbsp;&nbsp;&nbsp;&nbsp; * </p>
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @param data 已加密数据
&nbsp;&nbsp;&nbsp;&nbsp; * @param privateKey 私钥(BASE64编码)
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static String sign(byte[] data, String privateKey) throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] keyBytes = Base64Utils.decode(privateKey);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;signature.initSign(privateK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;signature.update(data);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Base64Utils.encode(signature.sign());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <p>
&nbsp;&nbsp;&nbsp;&nbsp; * 校验数字签名
&nbsp;&nbsp;&nbsp;&nbsp; * </p>
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @param data 已加密数据
&nbsp;&nbsp;&nbsp;&nbsp; * @param publicKey 公钥(BASE64编码)
&nbsp;&nbsp;&nbsp;&nbsp; * @param sign 数字签名
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static boolean verify(byte[] data, String publicKey, String sign)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] keyBytes = Base64Utils.decode(publicKey);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PublicKey publicK = keyFactory.generatePublic(keySpec);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;signature.initVerify(publicK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;signature.update(data);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return signature.verify(Base64Utils.decode(sign));
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <P>
&nbsp;&nbsp;&nbsp;&nbsp; * 私钥解密
&nbsp;&nbsp;&nbsp;&nbsp; * </p>
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @param encryptedData 已加密数据
&nbsp;&nbsp;&nbsp;&nbsp; * @param privateKey 私钥(BASE64编码)
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] keyBytes = Base64Utils.decode(privateKey);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cipher.init(Cipher.DECRYPT_MODE, privateK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int inputLen = encryptedData.length;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream out = new ByteArrayOutputStream();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int offSet = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] cache;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int i = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 对数据分段解密
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (inputLen - offSet > 0) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (inputLen - offSet > MAX_DECRYPT_BLOCK) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.write(cache, 0, cache.length);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offSet = i * MAX_DECRYPT_BLOCK;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] decryptedData = out.toByteArray();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.close();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return decryptedData;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <p>
&nbsp;&nbsp;&nbsp;&nbsp; * 公钥解密
&nbsp;&nbsp;&nbsp;&nbsp; * </p>
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @param encryptedData 已加密数据
&nbsp;&nbsp;&nbsp;&nbsp; * @param publicKey 公钥(BASE64编码)
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] keyBytes = Base64Utils.decode(publicKey);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Key publicK = keyFactory.generatePublic(x509KeySpec);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cipher.init(Cipher.DECRYPT_MODE, publicK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int inputLen = encryptedData.length;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream out = new ByteArrayOutputStream();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int offSet = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] cache;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int i = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 对数据分段解密
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (inputLen - offSet > 0) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (inputLen - offSet > MAX_DECRYPT_BLOCK) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.write(cache, 0, cache.length);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offSet = i * MAX_DECRYPT_BLOCK;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] decryptedData = out.toByteArray();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.close();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return decryptedData;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <p>
&nbsp;&nbsp;&nbsp;&nbsp; * 公钥加密
&nbsp;&nbsp;&nbsp;&nbsp; * </p>
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @param data 源数据
&nbsp;&nbsp;&nbsp;&nbsp; * @param publicKey 公钥(BASE64编码)
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static byte[] encryptByPublicKey(byte[] data, String publicKey)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] keyBytes = Base64Utils.decode(publicKey);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Key publicK = keyFactory.generatePublic(x509KeySpec);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 对数据加密
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cipher.init(Cipher.ENCRYPT_MODE, publicK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int inputLen = data.length;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream out = new ByteArrayOutputStream();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int offSet = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] cache;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int i = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 对数据分段加密
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (inputLen - offSet > 0) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (inputLen - offSet > MAX_ENCRYPT_BLOCK) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache = cipher.doFinal(data, offSet, inputLen - offSet);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.write(cache, 0, cache.length);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offSet = i * MAX_ENCRYPT_BLOCK;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] encryptedData = out.toByteArray();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.close();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return encryptedData;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <p>
&nbsp;&nbsp;&nbsp;&nbsp; * 私钥加密
&nbsp;&nbsp;&nbsp;&nbsp; * </p> 
&nbsp;&nbsp;&nbsp;&nbsp; * @param data 源数据
&nbsp;&nbsp;&nbsp;&nbsp; * @param privateKey 私钥(BASE64编码)
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] keyBytes = Base64Utils.decode(privateKey);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cipher.init(Cipher.ENCRYPT_MODE, privateK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int inputLen = data.length;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream out = new ByteArrayOutputStream();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int offSet = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] cache;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int i = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 对数据分段加密
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (inputLen - offSet > 0) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (inputLen - offSet > MAX_ENCRYPT_BLOCK) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cache = cipher.doFinal(data, offSet, inputLen - offSet);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.write(cache, 0, cache.length);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;offSet = i * MAX_ENCRYPT_BLOCK;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] encryptedData = out.toByteArray();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return encryptedData;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <p>
&nbsp;&nbsp;&nbsp;&nbsp; * 获取私钥
&nbsp;&nbsp;&nbsp;&nbsp; * </p> 
&nbsp;&nbsp;&nbsp;&nbsp; * @param keyMap 密钥对
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static String getPrivateKey(Map<String, Object> keyMap)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Key key = (Key) keyMap.get(PRIVATE_KEY);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Base64Utils.encode(key.getEncoded());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * <p>
&nbsp;&nbsp;&nbsp;&nbsp; * 获取公钥
&nbsp;&nbsp;&nbsp;&nbsp; * </p>
&nbsp;&nbsp;&nbsp;&nbsp; * 
&nbsp;&nbsp;&nbsp;&nbsp; * @param keyMap 密钥对
&nbsp;&nbsp;&nbsp;&nbsp; * @return
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;public static String getPublicKey(Map<String, Object> keyMap)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Key key = (Key) keyMap.get(PUBLIC_KEY);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Base64Utils.encode(key.getEncoded());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
 
&nbsp;&nbsp;&nbsp;&nbsp;public static String getEighteenIDCard(String fifteenIDCard)&#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder sb = new StringBuilder();&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(fifteenIDCard.substring(0, 6))&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.append("19")&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.append(fifteenIDCard.substring(6));&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(getVerifyCode(sb.toString()));&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return sb.toString();&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;/** 
&nbsp;&nbsp;&nbsp;&nbsp; * 获取校验码 
&nbsp;&nbsp;&nbsp;&nbsp; * @param idCardNumber 不带校验位的身份证号码（17位） 
&nbsp;&nbsp;&nbsp;&nbsp; * @return 校验码 
&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception 如果身份证没有加上19，则抛出异常 
&nbsp;&nbsp;&nbsp;&nbsp; */&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;private static char getVerifyCode(String idCardNumber)&#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char[] Ai = idCardNumber.toCharArray();&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int[] Wi = &#123;7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2&#125;;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char[] verifyCode = &#123;'1','0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'&#125;;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int S = 0;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int Y;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int i = 0; i < Wi.length; i++)&#123;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S += (Ai[i] - '0') * Wi[i];&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Y = S % 11;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return verifyCode[Y];&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) throws Exception &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map m = genKeyPair();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(getPrivateKey(m));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(getPublicKey(m));
&nbsp;&nbsp; &#125;
&#125;
</textarea><br/>Tags - <a href="https://www.heckjj.com/tags/rsa/" rel="tag">rsa</a> , <a href="https://www.heckjj.com/tags/%25E5%258A%25A0%25E5%25AF%2586/" rel="tag">加密</a> , <a href="https://www.heckjj.com/tags/%25E8%25A7%25A3%25E5%25AF%2586/" rel="tag">解密</a>
]]>
</description>
</item><item>
<link>https://www.heckjj.com/network-authentication-protocol-analysis/</link>
<title><![CDATA[总结破解网络验证(协议级的分析) ]]></title> 
<author>Heck &lt;@hecks.tk&gt;</author>
<category><![CDATA[加密破解]]></category>
<pubDate>Mon, 06 Sep 2010 06:32:01 +0000</pubDate> 
<guid>https://www.heckjj.com/network-authentication-protocol-analysis/</guid> 
<description>
<![CDATA[ 
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 微软雅黑;">在这里,沉淀太少,不敢多言,发出这篇总结,技术含量不高,意在抛砖引玉。昨年,有很多人想去破译别人的游戏外挂,也有更多的人最终失败.为什么失败的人比想去破译的人还多呢?因为有很多人他们不想破译,而是直接想拿到成品,换句话说,他们就是请人去破译的人.<br/>是啊,其实这个逻辑很简单,A找B去破译,B失败了,那么A自然就失败了.想去破译的人是B,而A只想得到个结果而已.<br/>其实,这个是一个最简单的协议.<br/>为什么要讲这么多呢?放心,看完前边的东西会对你后边的理解有莫大的帮助.<br/>首先我们来破译我们前边立出的那个最简单的协议.那个最简单的协议的流程大概是这样的:<br/>A&nbsp;&nbsp;找B 破译<br/>B&nbsp;&nbsp;破译&nbsp;&nbsp;成功告诉A,失败告诉A<br/>B成功,A成功.B失败,A失败.<br/><br/>好OK,这时候,我们进入下一轮的思考,我们在A和B之间穿插C,A通过C,找B,B返回给C,C再告诉A是否成功.——很显然,C的功能就是个代理的功能.<br/><br/>那么如果我们让C欺骗A,B的破译是成功的,那么很显然,A会认为B的破译是成功的.<br/><br/>是的欺诈,嗯,我们来谈谈欺诈这个很基础的思想,在网络验证中的一些简单的用法.</span><span style="font-family: 微软雅黑;"><br/><br/>对于游戏外挂这个东西.大多协议和执行流程是这样:<br/>情况1:<br/><br/>外挂首先连接外挂验证服务器.<br/><br/>然后外挂验证服务器返回成功或失败.<br/><br/>成功,外挂就会去连接游戏服务器,进行外挂功能扩展.<br/><br/>好谈到这里,我们就知道,一个很明确的概念,外挂验证是外挂验证,游戏验证是游戏验证,他们两个是丝毫没有关系的.唯一的存在的关键就是外挂验证成功,那么外挂功能代码就会执行.<br/><br/>好了,外挂验证和游戏验证就存在一个A和B的关系了.<br/><br/>这时候,我们就开始在外挂验证和游戏验证中穿插个C.相当于一个代理嘛.其实就是个欺诈点嘛.让外挂验证结果告诉C,在让C告诉A是否成功.<br/><br/>怎么穿插这个C呢?大概很多人都会想到以下几招:<br/>1.在外挂程序代码里,关于外挂验证的那断进行HOOK(HOOK是什么,HOOK是挂接),这样的方法建立在分析完外挂程序的基础上.<br/>2.在外挂验证的封包上进行截获,实现协议级的一个代理.从封包层面让外挂验证成功.这往往需要分析出其外挂验证的具体算法.<br/>3.建立在二的基础上,但是却不需要分析完外挂验证的全部数据,而是直接返回一个固定的成功包.<br/><br/>——————————-在这里,我谈谈,网络验证的流程.有个很简单的逻辑是这样的:正确的帐号+正确的密码 = 成功的封包.<br/>——————————-在这里,我再谈谈封包的截获.方法1:从写WS2_32,挂接connect,send,recv.(写很多代码)<br/>2,加密与解密3的DLL劫持技术.(都没仔细看,不知道是不是和方法3是一样的)<br/>3.其实可以直接用OD改WS2_32的connect.让它connct到本机的某个端口,再写个服务器监听那个端口,那个服务器的作用,就是接收,转发.具体的做法入下.<br/><br/>1.OD载入ws2_32,并找到connect的入口<br/><br/>71A24A07 >&nbsp;&nbsp;&nbsp;&nbsp;8BFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; edi, edi —–这里是我机器上的ws2_32的connect的入口<br/>71A24A09&nbsp;&nbsp; .&nbsp;&nbsp;55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;ebp<br/>71A24A0A&nbsp;&nbsp; .&nbsp;&nbsp;8BEC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp; ebp, esp<br/>71A24A0C&nbsp;&nbsp; .&nbsp;&nbsp;83EC 18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp;&nbsp; esp, 18<br/>71A24A0F&nbsp;&nbsp; .&nbsp;&nbsp;57&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push&nbsp;&nbsp;&nbsp;&nbsp;edi<br/>71A24A10&nbsp;&nbsp; .&nbsp;&nbsp;8D45 E8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lea&nbsp;&nbsp;&nbsp;&nbsp; eax, dword ptr [ebp-18]<br/><br/>用5个字节在前头写个jmp 到xxxxxx,—-跳到ws2_32.dll的缝隙,(HOOK API基础),然后写上这样的逻辑流.判断connect地址,如果是外挂验证服务器的地址,就连接到本机.(这里我就不写了.具体查看别人的文章,HOOK API和PE文件).在做之前,一定要改一改ws2_32.dll的pe文件属性,保证你跳到的地方,添加的代码可能执行.最后再用OD的功能,保存到可执行文件.保存之,就改好了,很省事.<br/><br/>好,到这里,我们就可以把外挂验证连到本机了,这时候我们写一个程序监听发送到本机固定端口的数据.监听后后,再转发给外挂验证服务器.其实这个过程相当于HOOK了send和recv.<br/><br/>这时候我们去买个正确的外挂帐号,很显然,发送一个正确的外挂,帐号和密码,到外挂验证服务器很显然,其会返回一个正确的包回来.好的,我们把这个正确的包的数据保存起.<br/><br/>存在我们那个中转的server里.然后再用一个错误帐号,去登陆,当然会返回一个错误的数据,这时候我们就在那个中转的server里把返回的错误数据换成正确的数据………那么外挂就截取了一个成功的包.恩,成了.外挂认为成功了.<br/><br/>呵呵!~~~其实这种可能性很微弱.因为外挂可能存在帐号名字的验证.比如是用户名aaa的成功封包不等于用户名BBB的成功封包,恩,这很正常.<br/><br/>好了,我们来把这微弱的曙光稍微变大一点,情况二,就是其外挂验证有用户名信息.这里说一说下边几种情况,外挂验证在建立TCP连接验证并返回封包后,持续保持连接,如果出现相同的用户名再去连接外挂验证明服务器,那它就断开连接.它这样做的目的,就是一个帐号,就只有一次登陆.<br/><br/>OK这里就扯蛋了,漏洞就在这里,如果,我们用一个代理去连接外挂服务器,然后我代理只跟外挂服务器建立一个连接.然后用代理,来不停的返回给外挂成功信息.<br/><br/>**,这不就成了.是啊,一个用成功的用户名和密码,就能让无数个外挂跑起来了.恩不错.就是这样.<br/><br/>实际这样容易破的外挂,确实还真的很少见.曙光依然很微弱,比起刚刚那点只强烈了点点.因为实际上大多数外挂验证的时候,别人都会在封包里加一个随机变量,一般是4个字节.Dword.<br/><br/>随意每次每次返回相同的成功封包,这招行不通啊.别个有随机啊.我们的招的前提,就是要每次返回相同的成功封包.<br/><br/>好了!~~无论多么牛B的验证方式,都有他多么牛B的破法,关键问题,我们怎么去思考一些问题.<br/><br/>好,这里给出一种思想让我们复用刚刚那招,返回同一个成功的包,我们必须得分析那几个随机变量的地址,然后把他们写死.<br/><br/>遗憾的是,大多数同志都战死在某某某强壳那里,根本就无法找到那4个字节的地址.<br/><br/>这里我就不谈能脱壳的程序怎么找随机变量了.我主要谈谈不能脱的时候怎么找.<br/><br/>方法1,很体力,很体力的过程,4个GB的内存地址,在每次send之后就写一段数据,如果随机变量是封包验证的关键,那么,用一个成功的帐号,发送一个成功的数据后,我们又把它的随机变量写之了,最终导致它,recv之后的验证,为失败.很明显，我们给了钱的,但是因为我们把随机变量写了,它就会觉得我们没给钱.<br/><br/>———这样的方法,要在4个G的内存中用排除找发.很黄,很暴力,也很累.<br/><br/>方法2.直接观测封包,一般情况,封包的算法不会太复杂,其变化会有一定的对应过程.恩,咱们直接看.凭感觉找.这个不好说,要跟到fell走.然后找出一些细节,根据接受,改变封包的返回.(这样的的希望大多也很渺茫)————其实封包的分析的关键,在于分析其内部的数据,大多都是有规律可寻的.很多时候根据具体情况具体处理.<br/><br/>—————————————————————————–到这里,对于不能脱壳的程序,用封包去破译的思想就到这里了—-因为很活,也不好说.其实,思想就一个,封包欺诈.<br/><br/>—————————————————————————————————<br/>这里我谈谈能脱的程序,杂破网络验证.<br/><br/>我这人贼懒,不习惯去逆别人的算法,硬去逆算法我会觉得很受不了,这也许是我一直很菜的原因.在这里要感谢finger,感谢那些脱壳脚本研究者,感谢党,感谢祖国的人民.或许没有他们的研究,就永远走不到脱壳后的的程序如何破解这写谈论上了.因为,我确实从来没用心去研究过壳这东西.深感惭愧.<br/><br/>外挂的验证方式千奇百怪,比如说昨年的那个天堂二天行者外挂,它大概的做法就是,外挂帐号,就是游戏帐号,验证后后就直接断开…你想麻,同一个游戏帐号不可能连续登陆两次三.<br/><br/>方法1:去把它的验证算法逆完.然后自己写验证服务器.(恩,我没有这样做)<br/>方法2:分析验证流程,找到一个关键点,换帐号.这个手法的关键是,找到程序里的关键流程,在外挂验证的时候,用一个收了钱的帐号去验证.但是在游戏验证的时候就把那个帐号换成你真的要登陆那个帐号.<br/><br/>哎呀,我的妈呀!~~那多困难啊.很多人可能会说.(**,这就是最简单的办法了.)….这样做的话,就能用一个帐号,登陆无数个帐号啊.<br/><br/>好了,再来谈个例子昨年有个51wg,出了个外挂,叫三国群英Online的外挂,脱机的,它更牛B,它会把用户数据在每次地图切换的时候,做一次数据验证,….恩,昨年的时候,根据我的分析,直接在它每次进行地图切换验证的时候,直接去把那个用户名换成个给了钱的用户名就KO了.<br/><br/>这个招的关键就是,外挂验证后会立刻断开连接.<br/><br/>——————————————————————————————————–<br/>再谈一个外挂,我当时看我朋友分析了分析,那外挂,定时用UDP发数据去验证,那壳又脱不掉,就那TMD壳….就是那个R2啥啥啥的.最后把那个sleep给他怎成永远,它的验证就各屁了.一般别人会开个线程,while(TRUE) sleep(1).等待接受数据.<br/>——————————————————————————————————<br/><br/>到这里,我大概阐述的也不是太清楚.其实关键就是,协议分析,然后根据协议分析得到的结论进行协议级的欺诈.<br/><br/>像我们的生活样.欺诈无处不在.所以大家一定要当心.<br/><br/>…………….无论写多么牛B的保护,不过大家在写之前,一定要把协议和顺序理一次.这样才可能事半功倍.否则会被猥亵的.<br/><br/>————-另外,某知名游戏保护…也存在思想上的漏洞….不过也是我朋友告诉我的,也不知道是不是.<br/><br/>完毕收工,很仓促,还有其它的工作要完成.</span><br/>Tags - <a href="https://www.heckjj.com/tags/%25E5%25A4%2596%25E6%258C%2582/" rel="tag">外挂</a> , <a href="https://www.heckjj.com/tags/%25E7%25A0%25B4%25E8%25A7%25A3/" rel="tag">破解</a> , <a href="https://www.heckjj.com/tags/%25E7%25BD%2591%25E7%25BB%259C%25E9%25AA%258C%25E8%25AF%2581/" rel="tag">网络验证</a> , <a href="https://www.heckjj.com/tags/%25E5%258D%258F%25E8%25AE%25AE%25E5%2588%2586%25E6%259E%2590/" rel="tag">协议分析</a>
]]>
</description>
</item>
</channel>
</rss>