From c7e91286dcfd2b620771449330c12afe3455dddf Mon Sep 17 00:00:00 2001 From: yexuejc <1107047387@qq.com> Date: Tue, 15 May 2018 15:19:47 +0800 Subject: [PATCH] 1.1.1 --- README.md | 2 +- UPDATE.md | 8 +- pom.xml | 11 +- .../com/yexuejc/base/encrypt/IOUtils.java | 249 ++++++++++++++++++ .../java/com/yexuejc/base/encrypt/RSA.java | 186 +++++++++++++ .../java/com/yexuejc/base/encrypt/RSA2.java | 62 +++++ 6 files changed, 515 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/yexuejc/base/encrypt/IOUtils.java create mode 100644 src/main/java/com/yexuejc/base/encrypt/RSA.java create mode 100644 src/main/java/com/yexuejc/base/encrypt/RSA2.java diff --git a/README.md b/README.md index c6f72fa..ec052de 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ### 使用 ->yexuejc.base.version=1.1.0 +>yexuejc.base.version=1.1.1 pom.xml ``` diff --git a/UPDATE.md b/UPDATE.md index 359a4f4..0afc010 100644 --- a/UPDATE.md +++ b/UPDATE.md @@ -1,7 +1,13 @@ yexuejc-base 更新记录 ------------------ -#### version :1.0.1 +#### version :1.1.1 +**time:** 2018-5-12 22:25:05
+**branch:** master
+**update:**
+>1.添加RSA + +##### version :1.1.0 **time:** 2018-5-12 22:25:05
**branch:** master
**update:**
diff --git a/pom.xml b/pom.xml index 17a7c8c..3adc195 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.yexuejc.base yexuejc-base - 1.1.0 + 1.1.1 ${project.artifactId} @@ -21,6 +21,7 @@ true 1.8 1.1.0.Final + 1.10 @@ -38,6 +39,14 @@ ${validation-api.version} true + + + commons-codec + commons-codec + ${commons-codec.version} + compile + true + diff --git a/src/main/java/com/yexuejc/base/encrypt/IOUtils.java b/src/main/java/com/yexuejc/base/encrypt/IOUtils.java new file mode 100644 index 0000000..cb2eea8 --- /dev/null +++ b/src/main/java/com/yexuejc/base/encrypt/IOUtils.java @@ -0,0 +1,249 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.yexuejc.base.encrypt; + +import java.io.*; + +/** + * General IO stream manipulation utilities. + *

+ * This class provides static utility methods for input/output operations. + *

+ *

+ * The byte-to-char methods and char-to-byte methods involve a conversion step. + * Two methods are provided in each case, one that uses the platform default + * encoding and the other which allows you to specify an encoding. You are + * encouraged to always specify an encoding because relying on the platform + * default can lead to unexpected results, for example when moving from + * development to production. + *

+ * All the methods in this class that read a stream are buffered internally. + * This means that there is no cause to use a BufferedInputStream + * or BufferedReader. The default buffer size of 4K has been shown + * to be efficient in tests. + *

+ * Wherever possible, the methods in this class do not flush or close + * the stream. This is to avoid making non-portable assumptions about the + * streams' origin and further use. Thus the caller is still responsible for + * closing streams after use. + *

+ * Origin of code: Excalibur. + */ +public class IOUtils { + // NOTE: This class is focused on InputStream, OutputStream, Reader and + // Writer. Each method should take at least one of these as a parameter, + // or return one of them. + + private static final int EOF = -1; + + /** + * The default buffer size ({@value}) to use for + * {@link #copyLarge(InputStream, OutputStream)} + * and + * {@link (Reader, Writer)} + */ + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + + /** + * Instances should NOT be constructed in standard programming. + */ + public IOUtils() { + super(); + } + + /** + * Closes a Closeable unconditionally. + *

+ * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in + * finally blocks. + *

+ * Example code: + *

+ *
+     * Closeable closeable = null;
+     * try {
+     *     closeable = new FileReader("foo.txt");
+     *     // process closeable
+     *     closeable.close();
+     * } catch (Exception e) {
+     *     // error handling
+     * } finally {
+     *     IOUtils.closeQuietly(closeable);
+     * }
+     * 
+ *

+ * Closing all streams: + *

+ *
+     * try {
+     *     return IOUtils.copy(inputStream, outputStream);
+     * } finally {
+     *     IOUtils.closeQuietly(inputStream);
+     *     IOUtils.closeQuietly(outputStream);
+     * }
+     * 
+ * + * @param closeable the objects to close, may be null or already closed + * @since 2.0 + */ + public static void closeQuietly(final Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (final IOException ioe) { + // ignore + } + } + + // copy from InputStream + //----------------------------------------------------------------------- + /** + * Copies bytes from an InputStream to an + * OutputStream. + *

+ * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

+ * Large streams (over 2GB) will return a bytes copied value of + * -1 after the copy has completed since the correct + * number of bytes cannot be returned as an int. For large streams + * use the copyLarge(InputStream, OutputStream) method. + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static int copy(final InputStream input, final OutputStream output) throws IOException { + final long count = copyLarge(input, output); + if (count > Integer.MAX_VALUE) { + return -1; + } + return (int) count; + } + + /** + * Copies bytes from a large (over 2GB) InputStream to an + * OutputStream. + *

+ * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

+ * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.3 + */ + public static long copyLarge(final InputStream input, final OutputStream output) + throws IOException { + + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + long count = 0; + int n = 0; + while (EOF != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } + + /** + * Reads bytes from an input stream. + * This implementation guarantees that it will read as many bytes + * as possible before giving up; this may not always be the case for + * subclasses of {@link InputStream}. + * + * @param input where to read input from + * @param buffer destination + * @param offset initial offset into buffer + * @param length length to read, must be >= 0 + * @return actual length read; may be less than requested if EOF was reached + * @throws IOException if a read error occurs + * @since 2.2 + */ + public static int read(final InputStream input, final byte[] buffer, final int offset, final int length) + throws IOException { + if (length < 0) { + throw new IllegalArgumentException("Length must not be negative: " + length); + } + int remaining = length; + while (remaining > 0) { + final int location = length - remaining; + final int count = input.read(buffer, offset + location, remaining); + if (EOF == count) { // EOF + break; + } + remaining -= count; + } + return length - remaining; + } + + /** + * Reads the requested number of bytes or fail if there are not enough left. + *

+ * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may + * not read as many bytes as requested (most likely because of reaching EOF). + * + * @param input where to read input from + * @param buffer destination + * @param offset initial offset into buffer + * @param length length to read, must be >= 0 + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if length is negative + * @throws EOFException if the number of bytes read was incorrect + * @since 2.2 + */ + public static void readFully(final InputStream input, final byte[] buffer, final int offset, final int length) + throws IOException { + final int actual = read(input, buffer, offset, length); + if (actual != length) { + throw new EOFException("Length to read: " + length + " actual: " + actual); + } + } + + /** + * Reads the requested number of bytes or fail if there are not enough left. + *

+ * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may + * not read as many bytes as requested (most likely because of reaching EOF). + * + * @param input where to read input from + * @param buffer destination + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if length is negative + * @throws EOFException if the number of bytes read was incorrect + * @since 2.2 + */ + public static void readFully(final InputStream input, final byte[] buffer) throws IOException { + readFully(input, buffer, 0, buffer.length); + } +} diff --git a/src/main/java/com/yexuejc/base/encrypt/RSA.java b/src/main/java/com/yexuejc/base/encrypt/RSA.java new file mode 100644 index 0000000..fa8c1e6 --- /dev/null +++ b/src/main/java/com/yexuejc/base/encrypt/RSA.java @@ -0,0 +1,186 @@ +package com.yexuejc.base.encrypt; + + +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; + +/** + * RSA加解密 配置模式 + * + * @ClassName: RSA + * @Description: + * @author: maxf + * @date: 2018/5/15 14:39 + */ +public class RSA { + + public static final String CHARSET = "UTF-8"; + public static final String RSA_ALGORITHM = "RSA"; + + public static Map initKeys(int keySize) { + //为RSA算法创建一个KeyPairGenerator对象 + KeyPairGenerator kpg; + try { + kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]"); + } + + //初始化KeyPairGenerator对象,密钥长度 + kpg.initialize(keySize); + //生成密匙对 + KeyPair keyPair = kpg.generateKeyPair(); + //得到公钥 + Key publicKey = keyPair.getPublic(); + String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded()); + //得到私钥 + Key privateKey = keyPair.getPrivate(); + String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded()); + Map keyPairMap = new HashMap(); + keyPairMap.put("publicKey", publicKeyStr); + keyPairMap.put("privateKey", privateKeyStr); + + return keyPairMap; + } + + + /** + * 得到公钥 + * + * @param publicKey 密钥字符串(经过base64编码) + * @throws Exception + */ + public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException { + //通过X509编码的Key指令获得公钥对象 + KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey)); + RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec); + return key; + } + + /** + * 得到私钥 + * + * @param privateKey 密钥字符串(经过base64编码) + * @throws Exception + */ + public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException { + //通过PKCS#8编码的Key指令获得私钥对象 + KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); + RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec); + return key; + } + + /** + * 公钥加密 + * + * @param data + * @param publicKey + * @return + */ + public static String publicEncrypt(String data, RSAPublicKey publicKey) { + try { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength())); + } catch (Exception e) { + throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e); + } + } + + /** + * 私钥解密 + * + * @param data + * @param privateKey + * @return + */ + + public static String privateDecrypt(String data, RSAPrivateKey privateKey) { + try { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET); + } catch (Exception e) { + throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e); + } + } + + /** + * 私钥加密 + * + * @param data + * @param privateKey + * @return + */ + + public static String privateEncrypt(String data, RSAPrivateKey privateKey) { + try { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength())); + } catch (Exception e) { + throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e); + } + } + + /** + * 公钥解密 + * + * @param data + * @param publicKey + * @return + */ + + public static String publicDecrypt(String data, RSAPublicKey publicKey) { + try { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET); + } catch (Exception e) { + throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e); + } + } + + private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) { + int maxBlock = 0; + if (opmode == Cipher.DECRYPT_MODE) { + maxBlock = keySize / 8; + } else { + maxBlock = keySize / 8 - 11; + } + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] buff; + int i = 0; + try { + while (datas.length > offSet) { + if (datas.length - offSet > maxBlock) { + buff = cipher.doFinal(datas, offSet, maxBlock); + } else { + buff = cipher.doFinal(datas, offSet, datas.length - offSet); + } + out.write(buff, 0, buff.length); + i++; + offSet = i * maxBlock; + } + } catch (Exception e) { + throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e); + } + byte[] resultDatas = out.toByteArray(); + IOUtils.closeQuietly(out); + return resultDatas; + } + +} diff --git a/src/main/java/com/yexuejc/base/encrypt/RSA2.java b/src/main/java/com/yexuejc/base/encrypt/RSA2.java new file mode 100644 index 0000000..508dbdd --- /dev/null +++ b/src/main/java/com/yexuejc/base/encrypt/RSA2.java @@ -0,0 +1,62 @@ +package com.yexuejc.base.encrypt; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * RSA加解密 证书模式 + * 依赖 {@link RSA} + * @ClassName: RSA2 + * @Description: + * @author: maxf + * @date: 2018/5/15 14:37 + */ +public class RSA2 { + + public static final String CHARSET = "UTF-8"; + public static final String RSA_ALGORITHM = "RSA"; + + /** + * 得到公钥 + * + * @param filepath 密钥文件路径 + * @throws Exception + */ + public static RSAPublicKey getPublicKey(String filepath) throws CertificateException, FileNotFoundException { + //通过证书,获取公钥 + CertificateFactory cf = null; + cf = CertificateFactory.getInstance("X.509"); + Certificate c = cf.generateCertificate(new FileInputStream(filepath)); + return (RSAPublicKey) c.getPublicKey(); + } + + /** + * 得到私钥 + * + * @param filepath 私钥路径 + * @param alias 证书别名 + * @param password 证书密码 + * @return + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws IOException + * @throws CertificateException + * @throws UnrecoverableKeyException + */ + public static RSAPrivateKey getPrivateKey(String filepath, String alias, String password) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException { + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(new FileInputStream(filepath), password.toCharArray()); + return (RSAPrivateKey) ks.getKey(alias, password.toCharArray()); + } + +}