參考了:
Java使用數字證書加密通訊(加解密/加簽驗籤)
https://www.cnblogs.com/shindo/p/6349070.htmlhtml
http://snowolf.iteye.com/blog/391931
Java加密技術(八)——數字證書java
http://snowolf.iteye.com/blog/735294
Java加密技術(十二)——.PFX(.p12)&我的信息交換文件算法
http://www.cnblogs.com/chnking/archive/2007/08/30/875947.html
使用X.509數字證書加密解密實務(二)-- 使用RSA證書加密敏感數據spring
證書組件工具類
CertificateCoder.javaspringboot
package test; import java.io.FileInputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Date; import java.util.Enumeration; import javax.crypto.Cipher; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * 證書組件 * * @author lijianbo * @version 1.0 * @since 1.0 */ public abstract class CertificateCoder { /** * Java密鑰�?Java Key Store,JKS)KEY_STORE */ public static final String KEY_STORE = "PKCS12"; public static final String X509 = "X.509"; // rsa 加密方式 public static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding"; /** * 由KeyStore得到私鑰 * * @param strPfxPath * @param strPassword * @return * @throws Exception */ private static PrivateKey getPrivateKey(String strPfxPath, String strPassword) throws Exception { try { KeyStore ks = KeyStore.getInstance("PKCS12"); FileInputStream fis = new FileInputStream(strPfxPath); // If the keystore password is empty(""), then we have to set // to null, otherwise it won't work!!! char[] nPassword = null; if ((strPassword == null) || strPassword.trim().equals("")){ nPassword = null; } else { nPassword = strPassword.toCharArray(); } ks.load(fis, nPassword); fis.close(); System.out.println("keystore type=" + ks.getType()); // Now we loop all the aliases, we need the alias to get keys. // It seems that this value is the "Friendly name" field in the // detals tab <-- Certificate window <-- view <-- Certificate // Button <-- Content tab <-- Internet Options <-- Tools menu // In MS IE 6. Enumeration enumas = ks.aliases(); String keyAlias = null; if (enumas.hasMoreElements())// we are readin just one certificate. { keyAlias = (String)enumas.nextElement(); System.out.println("alias=[" + keyAlias + "]"); } // Now once we know the alias, we could get the keys. System.out.println("is key entry=" + ks.isKeyEntry(keyAlias)); PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias, nPassword); Certificate cert = ks.getCertificate(keyAlias); PublicKey pubkey = cert.getPublicKey(); System.out.println("cert class = " + cert.getClass().getName()); System.out.println("cert = " + cert); System.out.println("public key = " + pubkey); System.out.println("private key = " + prikey); return prikey; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 由Certificate得到公鑰 * * @param certificatePath * @return * @throws Exception */ private static PublicKey getPublicKey(String certificatePath) throws Exception { Certificate certificate = getCertificate(certificatePath); PublicKey key = certificate.getPublicKey(); return key; } /** * 得到Certificate * * @param certificatePath * @return * @throws Exception */ private static Certificate getCertificate(String certificatePath) throws Exception { CertificateFactory certificateFactory = CertificateFactory.getInstance(X509); FileInputStream in = new FileInputStream(certificatePath); Certificate certificate = certificateFactory.generateCertificate(in); in.close(); return certificate; } /** * 得到Certificate * * @param keyStorePath * @param alias * @param password * @return * @throws Exception */ private static Certificate getCertificate(String keyStorePath, String alias, String password) throws Exception { KeyStore ks = getKeyStore(keyStorePath, password); Certificate certificate = ks.getCertificate(alias); return certificate; } /** * 得到KeyStore * * @param keyStorePath * @param password * @return * @throws Exception */ private static KeyStore getKeyStore(String keyStorePath, String password) throws Exception { FileInputStream is = new FileInputStream(keyStorePath); KeyStore ks = KeyStore.getInstance(KEY_STORE); ks.load(is, password.toCharArray()); is.close(); return ks; } /** * 私鑰加密 * * @param data * @param keyStorePath * @param alias * @param password * @return * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath, String password) throws Exception { // 取得私鑰 PrivateKey privateKey = getPrivateKey(keyStorePath, password); // 對數據加�? Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 私鑰解密 * * @param data * @param keyStorePath * @param alias * @param password * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath, String password) throws Exception { // 取得私鑰 PrivateKey privateKey = getPrivateKey(keyStorePath, password); // 對數據加�? Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 公鑰加密 * * @param data * @param certificatePath * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, String certificatePath) throws Exception { // 取得公鑰 PublicKey publicKey = getPublicKey(certificatePath); // 對數據加�? Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * 公鑰解密 * * @param data * @param certificatePath * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] data, String certificatePath) throws Exception { // 取得公鑰 PublicKey publicKey = getPublicKey(certificatePath); // 對數據加�? Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * 驗證Certificate * * @param certificatePath * @return */ public static boolean verifyCertificate(String certificatePath) { return verifyCertificate(new Date(), certificatePath); } /** * 驗證Certificate是否過時或無�? * * @param date * @param certificatePath * @return */ public static boolean verifyCertificate(Date date, String certificatePath) { boolean status = true; try { // 取得證書 Certificate certificate = getCertificate(certificatePath); // 驗證證書是否過時或無�? status = verifyCertificate(date, certificate); } catch (Exception e) { status = false; } return status; } /** * 驗證證書是否過時或無�? * * @param date * @param certificate * @return */ private static boolean verifyCertificate(Date date, Certificate certificate) { boolean status = true; try { X509Certificate x509Certificate = (X509Certificate) certificate; x509Certificate.checkValidity(date); } catch (Exception e) { status = false; } return status; } /** * 簽名 * * @param keyStorePath * @param alias * @param password * * @return * @throws Exception */ public static String sign(byte[] sign, String keyStorePath, String alias, String password) throws Exception { // 得到證書 X509Certificate x509Certificate = (X509Certificate) getCertificate( keyStorePath, alias, password); // 獲取私鑰 KeyStore ks = getKeyStore(keyStorePath, password); // 取得私鑰 PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password .toCharArray()); // 構建簽名 Signature signature = Signature.getInstance(x509Certificate .getSigAlgName()); signature.initSign(privateKey); signature.update(sign); return encryptBASE64(signature.sign()); } /** * 驗證簽名 * * @param data * @param sign * @param certificatePath * @return * @throws Exception */ public static boolean verify(byte[] data, String sign, String certificatePath) throws Exception { // 得到證書 X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath); // 得到公鑰 PublicKey publicKey = x509Certificate.getPublicKey(); // 構建簽名 Signature signature = Signature.getInstance(x509Certificate .getSigAlgName()); signature.initVerify(publicKey); signature.update(data); return signature.verify(decryptBASE64(sign)); } /** * 驗證Certificate * * @param keyStorePath * @param alias * @param password * @return */ public static boolean verifyCertificate(Date date, String keyStorePath, String alias, String password) { boolean status = true; try { Certificate certificate = getCertificate(keyStorePath, alias, password); status = verifyCertificate(date, certificate); } catch (Exception e) { status = false; } return status; } /** * 驗證Certificate * * @param keyStorePath * @param alias * @param password * @return */ public static boolean verifyCertificate(String keyStorePath, String alias, String password) { return verifyCertificate(new Date(), keyStorePath, alias, password); } /** * BASE64解密 * * @param key * @return * @throws Exception */ @SuppressWarnings("restriction") public static byte[] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } /** * BASE64加密 * * @param key * @return * @throws Exception */ @SuppressWarnings("restriction") public static String encryptBASE64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); } }
測試類:
加密、解密沒問題,可是簽名測試未經過,應該須要本身寫代碼了。app
package test; import static org.junit.Assert.*; import org.junit.Test; import com.example.springbootzuulgatwayproxy.encryption.CertificateCoder; /** * * @author 樑棟 * @version 1.0 * @since 1.0 */ public class CertificateCoderTest { private String password = "123456"; private String certificatePath = "C:/Users/bbo/Desktop/noprivate.cer"; private String keyStorePath = "C:/Users/bbo/Desktop/MyTest.pfx"; private String alias = "www.zlex.org"; @Test public void test() throws Exception { System.err.println("公鑰加密——私鑰解密"); String inputStr = "李建波"; byte[] data = inputStr.getBytes(); byte[] encrypt = CertificateCoder.encryptByPublicKey(data, certificatePath); byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt, keyStorePath, password); String outputStr = new String(decrypt); System.err.println("加密前: " + inputStr + "\n\r" + "解密後: " + outputStr); // 驗證數據一致 assertArrayEquals(data, decrypt); // 驗證證書有效 assertTrue(CertificateCoder.verifyCertificate(certificatePath)); } @Test public void testSign() throws Exception { System.err.println("私鑰加密——公鑰解密"); String inputStr = "sign"; byte[] data = inputStr.getBytes(); byte[] encodedData = CertificateCoder.encryptByPrivateKey(data, keyStorePath,password); byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData, certificatePath); String outputStr = new String(decodedData); System.err.println("加密前: " + inputStr + "\n\r" + "解密後: " + outputStr); assertEquals(inputStr, outputStr); System.err.println("私鑰簽名——公鑰驗證簽名"); // 產生簽名 String sign = CertificateCoder.sign(encodedData, alias ,keyStorePath, password); System.err.println("簽名:\r" + sign); // 驗證簽名 boolean status = CertificateCoder.verify(encodedData, sign, certificatePath); System.err.println("狀態:\r" + status); assertTrue(status); } }
獲取pfx文件的私鑰,並加密、解密測試:
測試經過,可使用。less
ReadPFX.javadom
package test; import java.io.FileInputStream; import java.io.InputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.util.Enumeration; import javax.crypto.Cipher; import javax.security.cert.X509Certificate; public class ReadPFX { public static void main(String[] args) throws Exception { String certificatePath = "C:/Users/bbo/Desktop/noprivate.cer"; String pfxString = "C:/Users/bbo/Desktop/MyTest.pfx"; String password = "123456"; String data = "李建波"; String RSA_TYPE = "RSA/ECB/PKCS1Padding"; // 獲取私鑰 ReadPFX pfx = new ReadPFX(); PrivateKey privateKey = pfx.GetPvkformPfx(pfxString, password); //獲取公鑰 InputStream inStream = new FileInputStream(certificatePath); X509Certificate cert = X509Certificate.getInstance(inStream); inStream.close(); PublicKey publicKey = cert.getPublicKey(); //加密 Cipher cipher = Cipher.getInstance(RSA_TYPE); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] b = data.getBytes(); /** 執行加密操做 */ byte[] b1 = cipher.doFinal(b); //Base64編碼,也能夠不用這一步 String encryption = new String(Base64.encodeBase64(b1), "UTF-8"); System.err.println("密文爲:" + encryption); /* * 解密 */ /** 獲得Cipher對象對已用公鑰加密的數據進行RSA解密 */ Cipher cipher2 = Cipher.getInstance(RSA_TYPE); cipher2.init(Cipher.DECRYPT_MODE, privateKey); //base64解碼 byte[] b2 = Base64.decodeBase64(encryption.getBytes()); /** 執行解密操做 */ byte[] b3 = cipher2.doFinal(b2); String decryption = new String(b3); System.err.println("明文爲:" + decryption); } public ReadPFX() { } // 轉換成十六進制字符串 public static String Byte2String(byte[] b) { String hs = ""; String stmp = ""; for (int n = 0; n < b.length; n++) { stmp = (java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length() == 1) hs = hs + "0" + stmp; else hs = hs + stmp; // if (n<b.length-1) hs=hs+":"; } return hs.toUpperCase(); } public static byte[] StringToByte(int number) { int temp = number; byte[] b = new byte[4]; for (int i = b.length - 1; i > -1; i--) { b[i] = new Integer(temp & 0xff).byteValue();// 將最高位保存在最低位 temp = temp >> 8; // 向右移8位 } return b; } public PrivateKey GetPvkformPfx(String strPfx, String strPassword) { try { KeyStore ks = KeyStore.getInstance("PKCS12"); FileInputStream fis = new FileInputStream(strPfx); // If the keystore password is empty(""), then we have to set // to null, otherwise it won't work!!! char[] nPassword = null; if ((strPassword == null) || strPassword.trim().equals("")) { nPassword = null; } else { nPassword = strPassword.toCharArray(); } ks.load(fis, nPassword); fis.close(); System.out.println("keystore type=" + ks.getType()); // Now we loop all the aliases, we need the alias to get keys. // It seems that this value is the "Friendly name" field in the // detals tab <-- Certificate window <-- view <-- Certificate // Button <-- Content tab <-- Internet Options <-- Tools menu // In MS IE 6. Enumeration enumas = ks.aliases(); String keyAlias = null; if (enumas.hasMoreElements())// we are readin just one certificate. { keyAlias = (String) enumas.nextElement(); System.out.println("alias=[" + keyAlias + "]"); } // Now once we know the alias, we could get the keys. System.out.println("is key entry=" + ks.isKeyEntry(keyAlias)); PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias, nPassword); Certificate cert = ks.getCertificate(keyAlias); PublicKey pubkey = cert.getPublicKey(); System.out.println("cert class = " + cert.getClass().getName()); System.out.println("cert = " + cert); System.out.println("public key = " + pubkey); System.out.println("private key = " + prikey); return prikey; } catch (Exception e) { e.printStackTrace(); } return null; } }
Base64工具類:ide
package test; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * * 描述:Base64加密 * * @author yangyongchuan 2016年11月8日 上午10:28:17 * @version 1.0 */ public class Base64 { /** * Chunk size per RFC 2045 section 6.8. * * <p> * The {@value} character limit does not count the trailing CRLF, but counts * all other characters, including any equal signs. * </p> * * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section * 6.8</a> */ static final int CHUNK_SIZE = 76; /** * Chunk separator per RFC 2045 section 2.1. * * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section * 2.1</a> */ static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes(); /** * The base length. */ static final int BASELENGTH = 255; /** * Lookup length. */ static final int LOOKUPLENGTH = 64; /** * Used to calculate the number of bits in a byte. */ static final int EIGHTBIT = 8; /** * Used when encoding something which has fewer than 24 bits. */ static final int SIXTEENBIT = 16; /** * Used to determine how many bits data contains. */ static final int TWENTYFOURBITGROUP = 24; /** * Used to get the number of Quadruples. */ static final int FOURBYTE = 4; /** * Used to test the sign of a byte. */ static final int SIGN = -128; /** * Byte used to pad output. */ static final byte PAD = (byte) '='; // Create arrays to hold the base64 characters and a // lookup for base64 chars private static byte[] base64Alphabet = new byte[BASELENGTH]; private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; // Populating the lookup and character arrays static { for (int i = 0; i < BASELENGTH; i++) { base64Alphabet[i] = (byte) -1; } for (int i = 'Z'; i >= 'A'; i--) { base64Alphabet[i] = (byte) (i - 'A'); } for (int i = 'z'; i >= 'a'; i--) { base64Alphabet[i] = (byte) (i - 'a' + 26); } for (int i = '9'; i >= '0'; i--) { base64Alphabet[i] = (byte) (i - '0' + 52); } base64Alphabet['+'] = 62; base64Alphabet['/'] = 63; for (int i = 0; i <= 25; i++) { lookUpBase64Alphabet[i] = (byte) ('A' + i); } for (int i = 26, j = 0; i <= 51; i++, j++) { lookUpBase64Alphabet[i] = (byte) ('a' + j); } for (int i = 52, j = 0; i <= 61; i++, j++) { lookUpBase64Alphabet[i] = (byte) ('0' + j); } lookUpBase64Alphabet[62] = (byte) '+'; lookUpBase64Alphabet[63] = (byte) '/'; } private static boolean isBase64(byte octect) { if (octect == PAD) { return true; } else if (base64Alphabet[octect] == -1) { return false; } else { return true; } } /** * Tests a given byte array to see if it contains only valid characters * within the Base64 alphabet. * * @param arrayOctect * byte array to test * @return true if all bytes are valid characters in the Base64 alphabet or * if the byte array is empty; false, otherwise */ public static boolean isArrayByteBase64(byte[] arrayOctect) { arrayOctect = discardWhitespace(arrayOctect); int length = arrayOctect.length; if (length == 0) { // shouldn't a 0 length array be valid base64 data? // return false; return true; } for (int i = 0; i < length; i++) { if (!isBase64(arrayOctect[i])) { return false; } } return true; } /** * Encodes binary data using the base64 algorithm but does not chunk the * output. * * @param binaryData * binary data to encode * @return Base64 characters */ public static byte[] encodeBase64(byte[] binaryData) { return encodeBase64(binaryData, false); } /** * Encodes binary data using the base64 algorithm and chunks the encoded * output into 76 character blocks * * @param binaryData * binary data to encode * @return Base64 characters chunked in 76 character blocks */ public static byte[] encodeBase64Chunked(byte[] binaryData) { return encodeBase64(binaryData, true); } /** * Decodes a byte[] containing containing characters in the Base64 alphabet. * * @param pArray * A byte array containing Base64 character data * @return a byte array containing binary data */ public static byte[] decode(byte[] pArray) { return decodeBase64(pArray); } /** * Encodes binary data using the base64 algorithm, optionally chunking the * output into 76 character blocks. * * @param binaryData * Array containing binary data to encode. * @param isChunked * if isChunked is true this encoder will chunk the base64 output * into 76 character blocks * @return Base64-encoded data. */ public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { int lengthDataBits = binaryData.length * EIGHTBIT; int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; byte encodedData[] = null; int encodedDataLength = 0; int nbrChunks = 0; if (fewerThan24bits != 0) { // data not divisible by 24 bit encodedDataLength = (numberTriplets + 1) * 4; } else { // 16 or 8 bit encodedDataLength = numberTriplets * 4; } // If the output is to be "chunked" into 76 character sections, // for compliance with RFC 2045 MIME, then it is important to // allow for extra length to account for the separator(s) if (isChunked) { nbrChunks = (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE)); encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length; } encodedData = new byte[encodedDataLength]; byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; int encodedIndex = 0; int dataIndex = 0; int i = 0; int nextSeparatorIndex = CHUNK_SIZE; int chunksSoFar = 0; for (i = 0; i < numberTriplets; i++) { dataIndex = i * 3; b1 = binaryData[dataIndex]; b2 = binaryData[dataIndex + 1]; b3 = binaryData[dataIndex + 2]; l = (byte) (b2 & 0x0f); k = (byte) (b1 & 0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex + 2] = lookUpBase64Alphabet[(l << 2) | val3]; encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f]; encodedIndex += 4; // If we are chunking, let's put a chunk separator down. if (isChunked) { // this assumes that CHUNK_SIZE % 4 == 0 if (encodedIndex == nextSeparatorIndex) { System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedIndex, CHUNK_SEPARATOR.length); chunksSoFar++; nextSeparatorIndex = (CHUNK_SIZE * (chunksSoFar + 1)) + (chunksSoFar * CHUNK_SEPARATOR.length); encodedIndex += CHUNK_SEPARATOR.length; } } } // form integral number of 6-bit groups dataIndex = i * 3; if (fewerThan24bits == EIGHTBIT) { b1 = binaryData[dataIndex]; k = (byte) (b1 & 0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4]; encodedData[encodedIndex + 2] = PAD; encodedData[encodedIndex + 3] = PAD; } else if (fewerThan24bits == SIXTEENBIT) { b1 = binaryData[dataIndex]; b2 = binaryData[dataIndex + 1]; l = (byte) (b2 & 0x0f); k = (byte) (b1 & 0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2]; encodedData[encodedIndex + 3] = PAD; } if (isChunked) { // we also add a separator to the end of the final chunk. if (chunksSoFar < nbrChunks) { System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedDataLength - CHUNK_SEPARATOR.length, CHUNK_SEPARATOR.length); } } return encodedData; } /** * Decodes Base64 data into octects * * @param base64Data * Byte array containing Base64 data * @return Array containing decoded data. */ public static byte[] decodeBase64(byte[] base64Data) { // RFC 2045 requires that we discard ALL non-Base64 characters base64Data = discardNonBase64(base64Data); // handle the edge case, so we don't have to worry about it later if (base64Data.length == 0) { return new byte[0]; } int numberQuadruple = base64Data.length / FOURBYTE; byte decodedData[] = null; byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; // Throw away anything not in base64Data int encodedIndex = 0; int dataIndex = 0; { // this sizes the output array properly - rlw int lastData = base64Data.length; // ignore the '=' padding while (base64Data[lastData - 1] == PAD) { if (--lastData == 0) { return new byte[0]; } } decodedData = new byte[lastData - numberQuadruple]; } for (int i = 0; i < numberQuadruple; i++) { dataIndex = i * 4; marker0 = base64Data[dataIndex + 2]; marker1 = base64Data[dataIndex + 3]; b1 = base64Alphabet[base64Data[dataIndex]]; b2 = base64Alphabet[base64Data[dataIndex + 1]]; if (marker0 != PAD && marker1 != PAD) { // No PAD e.g 3cQl b3 = base64Alphabet[marker0]; b4 = base64Alphabet[marker1]; decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); } else if (marker0 == PAD) { // Two PAD e.g. 3c[Pad][Pad] decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); } else if (marker1 == PAD) { // One PAD e.g. 3cQ[Pad] b3 = base64Alphabet[marker0]; decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); } encodedIndex += 3; } return decodedData; } /** * Discards any whitespace from a base-64 encoded block. * * @param data * The base-64 encoded data to discard the whitespace from. * @return The data, less whitespace (see RFC 2045). */ static byte[] discardWhitespace(byte[] data) { byte groomedData[] = new byte[data.length]; int bytesCopied = 0; for (int i = 0; i < data.length; i++) { switch (data[i]) { case (byte) ' ': case (byte) '\n': case (byte) '\r': case (byte) '\t': break; default: groomedData[bytesCopied++] = data[i]; } } byte packedData[] = new byte[bytesCopied]; System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); return packedData; } /** * Discards any characters outside of the base64 alphabet, per the * requirements on page 25 of RFC 2045 - "Any characters outside of the * base64 alphabet are to be ignored in base64 encoded data." * * @param data * The base-64 encoded data to groom * @return The data, less non-base64 characters (see RFC 2045). */ static byte[] discardNonBase64(byte[] data) { byte groomedData[] = new byte[data.length]; int bytesCopied = 0; for (int i = 0; i < data.length; i++) { if (isBase64(data[i])) { groomedData[bytesCopied++] = data[i]; } } byte packedData[] = new byte[bytesCopied]; System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); return packedData; } /** * Encodes a byte[] containing binary data, into a byte[] containing * characters in the Base64 alphabet. * * @param pArray * a byte array containing binary data * @return A byte array containing only Base64 character data */ public static byte[] encode(byte[] pArray) { return encodeBase64(pArray, false); } public static String encode(String str) throws UnsupportedEncodingException { String baseStr = new String(encode(str.getBytes("UTF-8"))); str = str.trim(); byte value[]; try { value = str.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { value = str.getBytes(); } MessageDigest md = null; try { md = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } byte[] input = md.digest(value); if (input == null) return null; StringBuffer output = new StringBuffer(input.length * 2); for (int i = 0; i < input.length; i++) { int current = input[i] & 0xff; if (current < 16) output.append("0"); output.append(Integer.toString(current, 16)); } String tempStr = output.toString().toUpperCase(); String result = tempStr + baseStr; return new String(encode(result.getBytes("UTF-8"))); } public static String decode(String cryptoStr) throws UnsupportedEncodingException { if (cryptoStr.length() < 40) return ""; try { String tempStr = new String(decode(cryptoStr.getBytes("UTF-8"))); String result = tempStr.substring(40, tempStr.length()); return new String(decode(result.getBytes("UTF-8"))); } catch (java.lang.ArrayIndexOutOfBoundsException ex) { return ""; } } /** * Decodes Base64 data into octects * * @param encoded * string containing Base64 data * @return Array containind decoded data. */ public static byte[] decode2(String encoded) { if (encoded == null) { return null; } char[] base64Data = encoded.toCharArray(); // remove white spaces int len = removeWhiteSpace(base64Data); if (len % FOURBYTE != 0) { return null;// should be divisible by four } int numberQuadruple = (len / FOURBYTE); if (numberQuadruple == 0) { return new byte[0]; } byte decodedData[] = null; byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; char d1 = 0, d2 = 0, d3 = 0, d4 = 0; int i = 0; int encodedIndex = 0; int dataIndex = 0; decodedData = new byte[(numberQuadruple) * 3]; for (; i < numberQuadruple - 1; i++) { if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) { return null; } // if found "no data" just return null b1 = base64Alphabet[d1]; b2 = base64Alphabet[d2]; b3 = base64Alphabet[d3]; b4 = base64Alphabet[d4]; decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); } if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { return null;// if found "no data" just return null } b1 = base64Alphabet[d1]; b2 = base64Alphabet[d2]; d3 = base64Data[dataIndex++]; d4 = base64Data[dataIndex++]; if (!isData((d3)) || !isData((d4))) {// Check if they are PAD characters if (isPad(d3) && isPad(d4)) { if ((b2 & 0xf) != 0)// last 4 bits should be zero { return null; } byte[] tmp = new byte[i * 3 + 1]; System.arraycopy(decodedData, 0, tmp, 0, i * 3); tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); return tmp; } else if (!isPad(d3) && isPad(d4)) { b3 = base64Alphabet[d3]; if ((b3 & 0x3) != 0)// last 2 bits should be zero { return null; } byte[] tmp = new byte[i * 3 + 2]; System.arraycopy(decodedData, 0, tmp, 0, i * 3); tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); return tmp; } else { return null; } } else { // No PAD e.g 3cQl b3 = base64Alphabet[d3]; b4 = base64Alphabet[d4]; decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); } return decodedData; } private static boolean isWhiteSpace(char octect) { return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); } private static boolean isData(char octect) { return (octect < BASELENGTH && base64Alphabet[octect] != -1); } private static boolean isPad(char octect) { return (octect == PAD); } /** * remove WhiteSpace from MIME containing encoded Base64 data. * * @param data * the byte array of base64 data (with WS) * @return the new length */ private static int removeWhiteSpace(char[] data) { if (data == null) { return 0; } // count characters that's not whitespace int newSize = 0; int len = data.length; for (int i = 0; i < len; i++) { if (!isWhiteSpace(data[i])) { data[newSize++] = data[i]; } } return newSize; } }
本身寫的RSA加密:工具
package cn.sccl.common.encrypt; /* * --------------------------------------------**********----------------------- * --------------------- * * 該算法於1977年由美國麻省理工學院MIT(Massachusetts Institute of Technology)的Ronal Rivest,Adi * Shamir和Len * Adleman三位年輕教授提出,並以三人的姓氏Rivest,Shamir和Adlernan命名爲RSA算法,是一個支持變長密鑰的公共密鑰算法, * 須要加密的文件快的長度也是可變的! * * 所謂RSA加密算法,是世界上第一個非對稱加密算法,也是數論的第一個實際應用。它的算法以下: * * 1.找兩個很是大的質數p和q(一般p和q都有155十進制位或都有512十進制位)並計算n=pq,k=(p-1)(q-1)。 * * 2.將明文編碼成整數M,保證M不小於0可是小於n。 * * 3.任取一個整數e,保證e和k互質,並且e不小於0可是小於k。加密鑰匙(稱做公鑰)是(e, n)。 * * 4.找到一個整數d,使得ed除以k的餘數是1(只要e和n知足上面條件,d確定存在)。解密鑰匙(稱做密鑰)是(d, n)。 * * 加密過程: 加密後的編碼C等於M的e次方除以n所得的餘數。 * * 解密過程: 解密後的編碼N等於C的d次方除以n所得的餘數。 * * 只要e、d和n知足上面給定的條件。M等於N。 * * --------------------------------------------**********----------------------- * --------------------- */ import java.math.BigInteger; 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.SecureRandom; import java.security.Signature; 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; /** * * 描述:RSA加密 * * @author yangyongchuan 2016年11月8日 上午10:16:44 * @version 1.0 */ public class RSA { /** 指定key的大小 */ private static int KEYSIZE = 1024; // 字符集 private final static String CHARACTER_SET = "UTF-8"; // rsa 加密方式 public static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding"; /** * * 描述:RSA 生成公鑰、私鑰對 * * @return * @throws Exception * @author yangyongchuan 2016年11月8日 上午10:16:56 * @version 1.0 */ public static Map<String, String> generateKeyPair() throws Exception { /** RSA算法要求有一個可信任的隨機數源 */ SecureRandom sr = new SecureRandom(); /** 爲RSA算法建立一個KeyPairGenerator對象 */ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); /** 利用上面的隨機數據源初始化這個KeyPairGenerator對象 */ kpg.initialize(KEYSIZE, sr); /** 生成密匙對 */ KeyPair kp = kpg.generateKeyPair(); /** 獲得公鑰 */ Key publicKey = kp.getPublic(); byte[] publicKeyBytes = publicKey.getEncoded(); String pub = new String(Base64.encodeBase64(publicKeyBytes), CHARACTER_SET); /** 獲得私鑰 */ Key privateKey = kp.getPrivate(); byte[] privateKeyBytes = privateKey.getEncoded(); String pri = new String(Base64.encodeBase64(privateKeyBytes), CHARACTER_SET); Map<String, String> map = new HashMap<String, String>(); map.put("publicKey", pub); map.put("privateKey", pri); RSAPublicKey rsp = (RSAPublicKey) kp.getPublic(); BigInteger bint = rsp.getModulus(); byte[] b = bint.toByteArray(); byte[] deBase64Value = Base64.encodeBase64(b); String retValue = new String(deBase64Value); map.put("modulus", retValue); return map; } /** * * 描述:加密:公鑰加密數據 * * @param source * @param publicKey * @return * @throws Exception * @author yangyongchuan 2016年11月8日 上午10:18:31 * @version 1.0 */ public static String encrypt(String source, String publicKey) throws Exception { Key key = getPublicKey(publicKey); /** 獲得Cipher對象來實現對源數據的RSA加密 */ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] b = source.getBytes(); /** 執行加密操做 */ byte[] b1 = cipher.doFinal(b); return new String(Base64.encodeBase64(b1), CHARACTER_SET); } /** * * 描述:解密:私鑰解密數據 * * @param cryptograph * @param privateKey * @return * @throws Exception * @author yangyongchuan 2016年11月8日 上午10:19:04 * @version 1.0 */ public static String decrypt(String cryptograph, String privateKey) throws Exception { Key key = getPrivateKey(privateKey); /** 獲得Cipher對象對已用公鑰加密的數據進行RSA解密 */ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, key); byte[] b1 = Base64.decodeBase64(cryptograph.getBytes()); /** 執行解密操做 */ byte[] b = cipher.doFinal(b1); return new String(b); } /** * * 描述:獲得公鑰:密鑰字符串(通過base64編碼) * * @param key * @return * @throws Exception * @author yangyongchuan 2016年11月8日 上午10:21:02 * @version 1.0 */ public static PublicKey getPublicKey(String key) throws Exception { X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(key.getBytes())); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(keySpec); return publicKey; } /** * * 描述: 獲得私鑰: 密鑰字符串(通過base64編碼) * * @param key * @return * @throws Exception * @author yangyongchuan 2016年11月8日 上午10:21:30 * @version 1.0 */ public static PrivateKey getPrivateKey(String key) throws Exception { PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key.getBytes())); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); return privateKey; } /** * * 描述:生成簽名 * * @param content * @param privateKey * @return * @author yangyongchuan 2016年11月8日 上午10:23:04 * @version 1.0 */ public static String sign(String content, String privateKey) { try { PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey.getBytes())); KeyFactory keyf = KeyFactory.getInstance("RSA"); PrivateKey priKey = keyf.generatePrivate(priPKCS8); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(priKey); signature.update(content.getBytes(CHARACTER_SET)); byte[] signed = signature.sign(); return new String(Base64.encodeBase64(signed)); } catch (Exception e) { } return null; } /** * * 描述:檢查簽名 * * @param content * @param sign * @param publicKey * @return * @author yangyongchuan 2016年11月8日 上午10:23:21 * @version 1.0 */ public static boolean checkSign(String content, String sign, String publicKey) { try { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); byte[] encodedKey = Base64.decode2(publicKey); PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA"); signature.initVerify(pubKey); signature.update(content.getBytes("utf-8")); boolean bverify = signature.verify(Base64.decode2(sign)); return bverify; } catch (Exception e) { e.printStackTrace(); } return false; } }