前⾔
数字签名、信息加密是前后端开发都经常需要使⽤到的技术,应⽤场景包括了⽤户登⼊、交易、信息通讯、oauth等等,不同的应⽤场景也会需要使⽤到不同的签名加密算法,或者需要搭配不⼀样的签名加密算法来达到业务⽬标。这⾥简单的给⼤家介绍⼏种常见的签名加密算法和⼀些典型场景下的应⽤。 正⽂
1. 数字签名
数字签名,简单来说就是通过提供可鉴别的数字信息验证⾃⾝⾝份的⼀种⽅式。⼀套数字签名通常定义两种互补的运算,⼀个⽤于签名,另⼀个⽤于验证。分别由发送者持有能够代表⾃⼰⾝份的私钥 (私钥不可泄露),由接受者持有与私钥对应的公钥,能够在接受到来⾃发送者信息时⽤于验证其⾝份。
注意:图中加密过程有别于公钥加密,更多。签名最根本的⽤途是要能够唯⼀证明发送⽅的⾝份,防⽌中间⼈攻击、CSRF跨域⾝份伪造。基于这⼀点在诸如设备认证、⽤户认证、第三⽅认证等认证体系中都会使⽤到签名算法 (彼此的实现⽅式可能会有差异)。
2. 加密和解密
2.1. 加密
数据加密的基本过程,就是对原来为明⽂的⽂件或数据按某种算法进⾏处理,使其成为不可读的⼀段代码,通常称为 “密⽂”。通过这样的途径,来达到保护数据不被⾮法⼈窃取、阅读的⽬的。
2.2. 解密
加密的逆过程为解密,即将该编码信息转化为其原来数据的过程。
3. 对称加密和⾮对称加密
加密算法分对称加密和⾮对称加密,其中对称加密算法的加密与解密密钥相同,⾮对称加密算法的加密密钥与解密密钥不同,此外,还有⼀类不需要密钥的散列算法。 常见的对称加密算法主要有DES、3DES、AES等,常见的⾮对称算法主要有RSA、DSA等,散列算法主要有SHA-1、MD5等。
3.1. 对称加密
对称加密算法是应⽤较早的加密算法,⼜称为共享密钥加密算法。在对称加密算法中,使⽤的密钥只
有⼀个,发送和接收双⽅都使⽤这个密钥对数据进⾏加密和解密。这就要求加密和解密⽅事先都必须知道加密的密钥。
1. 数据加密过程:在对称加密算法中,数据发送⽅将明⽂ (原始数据) 和加密密钥⼀起经过特殊加密处理,⽣成复杂的加密密⽂进⾏发送。
2. 数据解密过程:数据接收⽅收到密⽂后,若想读取原数据,则需要使⽤加密使⽤的密钥及相同算法的逆算法对加密的密⽂进⾏解密,才能使其恢复成可读明⽂。
3.2. ⾮对称加密
⾮对称加密算法,⼜称为公开密钥加密算法。它需要两个密钥,⼀个称为公开密钥 (public key),即公钥,另⼀个称为私有密钥 (private key),即私钥。
因为加密和解密使⽤的是两个不同的密钥,所以这种算法称为⾮对称加密算法。
1. 如果使⽤公钥对数据进⾏加密,只有⽤对应的私钥才能进⾏解密。
2. 如果使⽤私钥对数据进⾏加密,只有⽤对应的公钥才能进⾏解密。
例⼦:甲⽅⽣成⼀对密钥并将其中的⼀把作为公钥向其它⼈公开,得到该公钥的⼄⽅使⽤该密钥对机密信息进⾏加密后再发送给甲⽅,甲⽅再使⽤⾃⼰保存的另⼀把专⽤密钥 (私钥),对加密后的信息进⾏解密。
4. 常见的签名加密算法
4.1. MD5算法
MD5⽤的是哈希函数,它的典型应⽤是对⼀段信息产⽣信息摘要,以防⽌被篡改。严格来说,MD5不是⼀种加密算法⽽是摘要算法。⽆论是多长的输⼊,MD5都会输出长度为128bits的⼀个串 (通常⽤16进制表⽰为32个字符)。
public static final byte[] computeMD5(byte[] content) {
try {
MessageDigest md5 = Instance("MD5");
return md5.digest(content);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
复制代码
4.2. SHA1算法
SHA1是和MD5⼀样流⾏的消息摘要算法,然⽽SHA1⽐MD5的安全性更强。对于长度⼩于2 ^ 64位的消息,SHA1会产⽣⼀个160位的消息摘要。基于MD5、SHA1的信息摘要特性以及不可逆 (⼀般⽽⾔),可以被应⽤在检查⽂件完整性以及数字签名等场景。
public static byte[] computeSHA1(byte[] content) {
try {
MessageDigest sha1 = Instance("SHA1");
return sha1.digest(content);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
复制代码
4.3. HMAC算法
HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC运算利⽤哈希算法 (MD5、SHA1等),以⼀个密钥和⼀个消息为输⼊,⽣成⼀个消息摘要作为输出。
HMAC发送⽅和接收⽅都有的key进⾏计算,⽽没有这把key的第三⽅,则是⽆法计算出正确的散列值的,这样就可以防⽌数据被篡改。
package net.pocrd.util;
import net.pocrd.annotation.NotThreadSafe;
import net.pocrd.define.ConstField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
pto.Mac;
pto.SecretKey;
pto.spec.SecretKeySpec;
import java.util.Arrays;
@NotThreadSafe
public class HMacHelper {
private static final Logger logger = Logger(HMacHelper.class);
private Mac mac;
<span class="hljs-comment">/**
* MAC算法可选以下多种算法
* HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512
*/</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String KEY_MAC = <span class="hljs-string">"HmacMD5"</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HMacHelper</span><span class="hljs-params">(String key)</span> </span>{
<span class="hljs-keyword">try</span> {
SecretKey secretKey = <span class="hljs-keyword">new</span> Bytes(ConstField.UTF8), KEY_MAC);
mac = Algorithm());
mac.init(secretKey);
} <span class="hljs-keyword">catch</span> (Exception e) {
<(<span class="hljs-string">"create hmac helper failed."</span>, e);
}
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] sign(<span class="hljs-keyword">byte</span>[] content) {
<span class="hljs-keyword">return</span> mac.doFinal(content);
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">verify</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] signature, <sp <span class="hljs-keyword">try</span> {
<span class="hljs-keyword">byte</span>[] result = mac.doFinal(content);
<span class="hljs-keyword">return</span> Arrays.equals(signature, result);
} <span class="hljs-keyword">catch</span> (Exception e) {
<(<span class="hljs-string">"verify sig failed."</span>, e);
}
<span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
}
}
复制代码
测试结论:HMAC算法实例在多线程环境下是不安全的。但是需要在多线程访问时,进⾏同步的辅助类,使⽤ThreadLocal为每个线程缓存⼀个实例可以避免进⾏锁
操作。
4.4. AES/DES/3DES算法
AES、DES、3DES都是对称的块加密算法,加解密的过程是可逆的。常⽤的有AES128、AES192、AES256 (默认安装的JDK尚不⽀持AES256,需要安装对应的jce补丁进⾏升级
jce1.7,jce1.8)。
4.4.1. DES算法
DES加密算法是⼀种分组密码,以64位为分组对数据加密,它的密钥长度是56位,加密解密⽤同⼀算法。
DES加密算法是对密钥进⾏保密,⽽公开算法,包括加密和解密算法。这样,只有掌握了和发送⽅相同密钥的⼈才能解读由DES加密算法加密的密⽂数据。因此,破译DES加
密算法实际上就是搜索密钥的编码。对于56位长度的密钥来说,如果⽤穷举法来进⾏搜索的话,其运算次数为2 ^ 56次。
4.4.2. 3DES算法
是基于DES的对称算法,对⼀块数据⽤三个不同的密钥进⾏三次加密,强度更⾼。
4.4.3. AES算法
AES加密算法是密码学中的⾼级加密标准,该加密算法采⽤对称分组密码体制,密钥长度的最少⽀持为128位、192位、256位,分组长度128位,算法应易于各种硬件和软件实
现。这种加密算法是美国联邦政府采⽤的区块加密标准。
AES本⾝就是为了取代DES的,AES具有更好的安全性、效率和灵活性。
import net.pocrd.annotation.NotThreadSafe;
pto.Cipher;
pto.KeyGenerator;
pto.spec.IvParameterSpec;
pto.spec.SecretKeySpec;
import java.security.SecureRandom;
@NotThreadSafe
public class AesHelper {
private SecretKeySpec keySpec;
private IvParameterSpec iv;
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AesHelper</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] aesKey, <span class="hljs-keyword">byte</span>[] iv) <span class="hljs-keyword">if</span> (aesKey == <span class="hljs-keyword">null</span> || aesKey.length < <span class="hljs-number">16</span> || (iv != <span class="hljs-keyword">null</span> && iv.length < <span clas <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"错误的初始密钥"</span>);
}
<span class="hljs-keyword">if</span> (iv == <span class="hljs-keyword">null</span>) {
iv = pute(aesKey);
}
keySpec = <span class="hljs-keyword">new</span> SecretKeySpec(aesKey, <span class="hljs-string">"AES"</span>);
<span class="hljs-keyword">this</span>.iv = <span class="hljs-keyword">new</span> IvParameterSpec(iv);
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AesHelper</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] aesKey)</span> </span>{
<span class="hljs-keyword">if</span> (aesKey == <span class="hljs-keyword">null</span> || aesKey.length < <span class="hljs-number">16</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"错误的初始密钥"</span>);
}
keySpec = <span class="hljs-keyword">new</span> SecretKeySpec(aesKey, <span class="hljs-string">"AES"</span>);
<span class="hljs-keyword">this</span>.iv = <span class="hljs-keyword">new</span> pute(aesKey));
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] encrypt(<span class="hljs-keyword">byte</span>[] data) {
<span class="hljs-keyword">byte</span>[] result = <span class="hljs-keyword">null</span>;
Cipher cipher = <span class="hljs-keyword">null</span>;
<span class="hljs-keyword">try</span> {
cipher = Instance(<span class="hljs-string">"AES/CFB/NoPadding"</span>);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
result = cipher.doFinal(data);
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
<span class="hljs-keyword">return</span> result;
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] decrypt(<span class="hljs-keyword">byte</span>[] secret) {
<span class="hljs-keyword">byte</span>[] result = <span class="hljs-keyword">null</span>;
Cipher cipher = <span class="hljs-keyword">null</span>;
<span class="hljs-keyword">try</span> {
cipher = Instance(<span class="hljs-string">"AES/CFB/NoPadding"</span>);
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
result = cipher.doFinal(secret);
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
<span class="hljs-keyword">return</span> result;
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">byte</span>[] randomKey(<span class="hljs-keyword">int</span> size) {
<span class="hljs-keyword">byte</span>[] result = <span class="hljs-keyword">null</span>;
<span class="hljs-keyword">try</span> {
KeyGenerator gen = Instance(<span class="hljs-string">"AES"</span>);
gen.init(size, <span class="hljs-keyword">new</span> SecureRandom());
result = ateKey().getEncoded();
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
<span class="hljs-keyword">return</span> result;
}
}
复制代码
4.5. RSA算法
RSA加密算法是⽬前最有影响⼒的公钥加密算法,并且被普遍认为是⽬前最优秀的公钥⽅案之⼀。RSA是第⼀个能同时⽤于加密和数字签名的算法,它能够抵抗到⽬前为⽌
已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。
RSA加密算法基于⼀个⼗分简单的数论事实:将两个⼤素数相乘⼗分容易,但想要对其乘积进⾏因式分解却极其困难,因此可以将乘积公开作为加密密钥。
import net.pocrd.annotation.NotThreadSafe;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
pto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@NotThreadSafe
public class RsaHelper {
private static final Logger logger = Logger(RsaHelper.class);
private RSAPublicKey publicKey;
private RSAPrivateCrtKey privateKey;
<span class="hljs-keyword">static</span> {
Security.addProvider(<span class="hljs-keyword">new</span> BouncyCastleProvider()); <span class="hljs-comment">//使⽤bouncycastle作为加密算法实现</span>
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">RsaHelper</span><span class="hljs-params">(String publicKey, String privateKey)</span> </span>{
<span class="hljs-keyword">this</span>(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">RsaHelper</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] publicKey, <span class="hljs-keyword">byte</span>[] p <span class="hljs-keyword">try</span> {
KeyFactory keyFactory = Instance(<span class="hljs-string">"RSA"</span>);
<span class="hljs-keyword">if</span> (publicKey != <span class="hljs-keyword">null</span> && publicKey.length > <span class="hljs-number">0</span>) {
<span class="hljs-keyword">this</span>.publicKey = (atePublic(<span class="hljs-keyword">new</span> X509EncodedKeySpec(publicKey));
}
<span class="hljs-keyword">if</span> (privateKey != <span class="hljs-keyword">null</span> && privateKey.length > <span class="hljs-number">0</span>) {
<span class="hljs-keyword">this</span>.privateKey = (atePrivate(<span class="hljs-keyword">new</span> PKCS8EncodedKeySpec(privateKey));
}
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">RsaHelper</span><span class="hljs-params">(String publicKey)</span> </span>{
<span class="hljs-keyword">this</span>(Base64Util.decode(publicKey));
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">RsaHelper</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] publicKey)</span> </span>{
<span class="hljs-keyword">try</span> {
KeyFactory keyFactory = Instance(<span class="hljs-string">"RSA"</span>);
<span class="hljs-keyword">if</span> (publicKey != <span class="hljs-keyword">null</span> && publicKey.length > <span class="hljs-number">0</span>) {
<span class="hljs-keyword">this</span>.publicKey = (atePublic(<span class="hljs-keyword">new</span> X509EncodedKeySpec(publicKey));
}
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] encrypt(<span class="hljs-keyword">byte</span>[] content) {
<span class="hljs-keyword">if</span> (publicKey == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"public key is null."</span>);
}
<span class="hljs-keyword">if</span> (content == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}
<span class="hljs-keyword">try</span> {
Cipher cipher = Instance(<span class="hljs-string">"RSA/ECB/PKCS1Padding"</span>);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
<span class="hljs-keyword">int</span> size = Modulus().bitLength() / <span class="hljs-number">8</span> - <span class="hljs-number">11</span>;
ByteArrayOutputStream baos = <span class="hljs-keyword">new</span> ByteArrayOutputStream((content.length + size - <span class="hljs-number">1</span>) / size * (size + <span class="hljs-number">11</span>));
<span class="hljs-keyword">int</span> left = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < content.length; ) {
left = content.length - i;
<span class="hljs-keyword">if</span> (left > size) {
cipher.update(content, i, size);
i += size;
} <span class="hljs-keyword">else</span> {
cipher.update(content, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
<span class="hljs-keyword">return</span> ByteArray();
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] decrypt(<span class="hljs-keyword">byte</span>[] secret) {
<span class="hljs-keyword">if</span> (privateKey == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"private key is null."</span>);
}
<span class="hljs-keyword">if</span> (secret == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}
<span class="hljs-keyword">try</span> {
Cipher cipher = Instance(<span class="hljs-string">"RSA/ECB/PKCS1Padding"</span>);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
<span class="hljs-keyword">int</span> size = Modulus().bitLength() / <span class="hljs-number">8</span>;
ByteArrayOutputStream baos = <span class="hljs-keyword">new</span> ByteArrayOutputStream((secret.length + size - <span class="hljs-number">12</span>) / (size - <span class="hljs-number">11</span>) * size);
<span class="hljs-keyword">int</span> left = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < secret.length; ) {
left = secret.length - i;
<span class="hljs-keyword">if</span> (left > size) {
cipher.update(secret, i, size);
i += size;
} <span class="hljs-keyword">else</span> {
cipher.update(secret, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
<span class="hljs-keyword">return</span> ByteArray();
} <span class="hljs-keyword">catch</span> (Exception e) {
<(<span class="hljs-string">"rsa decrypt failed."</span>, e);
}
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] sign(<span class="hljs-keyword">byte</span>[] content) {
<span class="hljs-keyword">if</span> (privateKey == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"private key is null."</span>);
}
<span class="hljs-keyword">if</span> (content == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}
<span class="hljs-keyword">try</span> {
Signature signature = Instance(<span class="hljs-string">"SHA1WithRSA"</span>);
signature.initSign(privateKey);
signature.update(content);
<span class="hljs-keyword">return</span> signature.sign();
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">verify</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] sign, <span cl <span class="hljs-keyword">if</span> (publicKey == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"public key is null."</span>);
}
<span class="hljs-keyword">if</span> (sign == <span class="hljs-keyword">null</span> || content == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
}
<span class="hljs-keyword">try</span> {
Signature signature = Instance(<span class="hljs-string">"SHA1WithRSA"</span>);
signature.initVerify(publicKey);
signature.update(content);
<span class="hljs-keyword">return</span> signature.verify(sign);
} <span class="hljs-keyword">catch</span> (Exception e) {
<(<span class="hljs-string">"rsa verify failed."</span>, e);
}
<span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
}
}
复制代码
4.6. ECC算法
ECC也是⼀种⾮对称加密算法,主要优势是在某些情况下,它⽐其他的⽅法使⽤更⼩的密钥,⽐如RSA加密算法,提供相当的或更⾼等级的安全级别。不过⼀个缺点是加密和
解密操作的实现⽐其他机制时间长 (相⽐RSA算法,该算法对CPU消耗严重)。
import net.pocrd.annotation.NotThreadSafe;
import org.bouncycastle.jcajce.BCECPrivateKey;
import org.bouncycastle.jcajce.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
pto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@NotThreadSafe
public class EccHelper {
private static final Logger logger = Logger(EccHelper.class);
private static final int SIZE = 4096;
private BCECPublicKey publicKey;
private BCECPrivateKey privateKey;
<span class="hljs-keyword">static</span> {
Security.addProvider(<span class="hljs-keyword">new</span> BouncyCastleProvider());
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">EccHelper</span><span class="hljs-params">(String publicKey, String privateKey)</span> </span>{
<span class="hljs-keyword">this</span>(Base64Util.decode(publicKey), Base64Util.decode(privateKey));
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">EccHelper</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] publicKey, <span class="hljs-keyword">byte</span>[] p <span class="hljs-keyword">try</span> {
KeyFactory keyFactory = Instance(<span class="hljs-string">"EC"</span>, <span class="hljs-string">"BC"</span>);
<span class="hljs-keyword">if</span> (publicKey != <span class="hljs-keyword">null</span> && publicKey.length > <span class="hljs-number">0</span>) {
<span class="hljs-keyword">this</span>.publicKey = (atePublic(<span class="hljs-keyword">new</span> X509EncodedKeySpec(publicKey));
}
<span class="hljs-keyword">if</span> (privateKey != <span class="hljs-keyword">null</span> && privateKey.length > <span class="hljs-number">0</span>) {
<span class="hljs-keyword">this</span>.privateKey = (atePrivate
(<span class="hljs-keyword">new</span> PKCS8EncodedKeySpec(privateKey));
}
} <span class="hljs-keyword">catch</span> (ClassCastException e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">""</span>, e);
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">EccHelper</span><span class="hljs-params">(String publicKey)</span> </span>{
<span class="hljs-keyword">this</span>(Base64Util.decode(publicKey));
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">EccHelper</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] publicKey)</span> </span>{
<span class="hljs-keyword">try</span> {
KeyFactory keyFactory = Instance(<span class="hljs-string">"EC"</span>, <span class="hljs-string">"BC"</span>);
<span class="hljs-keyword">if</span> (publicKey != <span class="hljs-keyword">null</span> && publicKey.length > <span class="hljs-number">0</span>) {
<span class="hljs-keyword">this</span>.publicKey = (atePublic(<span class="hljs-keyword">new</span> X509EncodedKeySpec(publicKey));
}
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] encrypt(<span class="hljs-keyword">byte</span>[] content) {
<span class="hljs-keyword">if</span> (publicKey == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"public key is null."</span>);
}
<span class="hljs-keyword">try</span> {
Cipher cipher = Instance(<span class="hljs-string">"ECIES"</span>, <span class="hljs-string">"BC"</span>);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
<span class="hljs-keyword">int</span> size = SIZE;
ByteArrayOutputStream baos = <span class="hljs-keyword">new</span> ByteArrayOutputStream((content.length + size - <span class="hljs-number">1</span>) / size * (size + <span class="hljs-number">45</span>));
<span class="hljs-keyword">int</span> left = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < content.length; ) {
left = content.length - i;
<span class="hljs-keyword">if</span> (left > size) {
cipher.update(content, i, size);
i += size;
} <span class="hljs-keyword">else</span> {
cipher.update(content, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
<span class="hljs-keyword">return</span> ByteArray();
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(e);
}
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] decrypt(<span class="hljs-keyword">byte</span>[] secret) {
<span class="hljs-keyword">if</span> (privateKey == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"private key is null."</span>);
}
<span class="hljs-keyword">try</span> {
Cipher cipher = Instance(<span class="hljs-string">"ECIES"</span>, <span class="hljs-string">"BC"</span>);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
<span class="hljs-keyword">int</span> size = SIZE + <span class="hljs-number">45</span>;
ByteArrayOutputStream baos = <span class="hljs-keyword">new</span> ByteArrayOutputStream((secret.length + size + <span class="hljs-number">44</span>) / (size + <span class="hljs-number">45</span>) * size);
<span class="hljs-keyword">int</span> left = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < secret.length; ) {
left = secret.length - i;
<span class="hljs-keyword">if</span> (left > size) {
cipher.update(secret, i, size);
i += size;
} <span class="hljs-keyword">else</span> {
cipher.update(secret, i, left);
i += left;
}
baos.write(cipher.doFinal());
}
<span class="hljs-keyword">return</span> ByteArray();
} <span class="hljs-keyword">catch</span> (Exception e) {
<(<span class="hljs-string">"ecc decrypt failed."</span>, e);
}
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">byte</span>[] sign(<span class="hljs-keyword">byte</span>[] content) {
<span class="hljs-keyword">if</span> (privateKey == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"private key is null."</span>);
}
<span class="hljs-keyword">try</span> {
Signature signature = Instance(<span class="hljs-string">"SHA1withECDSA"</span>, <span class="hljs-string">"BC"</span>);
signature.initSign(privateKey);
signature.update(content);
<span class="hljs-keyword">return</span> signature.sign();
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeExcept
ion(e);
}
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">verify</span><span class="hljs-params">(<span class="hljs-keyword">byte</span>[] sign, <span cl <span class="hljs-keyword">if</span> (publicKey == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"public key is null."</span>);
}
<span class="hljs-keyword">try</span> {
Signature signature = Instance(<span class="hljs-string">"SHA1withECDSA"</span>, <span class="hljs-string">"BC"</span>);
signature.initVerify(publicKey);
signature.update(content);
<span class="hljs-keyword">return</span> signature.verify(sign);
} <span class="hljs-keyword">catch</span> (Exception e) {
<(<span class="hljs-string">"ecc verify failed."</span>, e);
}
<span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
}