項目裡有各種加密方法,但從來沒有仔細研究過。一般只是copy。這幾天遇到一些問題,看了一下加密代碼,覺得有些疑惑。
我們知道jdk已經為我們包裝好了很多的算法。但究竟包裝了哪些算法,怎麼去掉這些算法我並沒有去查過。今天跟了一下源碼,大概知道了。
首先要從下面這幾行代碼說起:
KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
對於AES加密,我們用KeyGenerator kgen = KeyGenerator.getInstance("AES");,MD5我們用java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");,這裡從方法上看出java類是通過一個算法名稱去找的,比如AES,但源碼中並沒有把算法名稱包裝為枚舉,我們無法得知KeyGenerator除了有AES算法,還能獲得那些算法,而且如何獲得KeyGenerator的算法名稱,比如AES不全是大寫會不會有問題,KeyGenerator是不是有MD5等等。
打開KeyGenerator.getInstance()方法,看其源碼
public static final KeyGenerator getInstance(String paramString) throws NoSuchAlgorithmException { return new KeyGenerator(paramString); }
我們發現直接調用了構造方法,查看構造方法:
private KeyGenerator(String paramString) throws NoSuchAlgorithmException { this.algorithm = paramString; List localList = GetInstance.getServices("KeyGenerator", paramString); this.serviceIterator = localList.iterator(); this.initType = 1; if (nextSpi(null, false) == null) { throw new NoSuchAlgorithmException(paramString + " KeyGenerator not available"); } if ((!skipDebug) && (pdebug != null)) { pdebug.println("KeyGenerator." + paramString + " algorithm from: " + this.provider .getName()); } }
構造方法其實是通過GetInstance.getServices("KeyGenerator", paramString)去找到,繼續跟進
public Provider.Service getService(String paramString1, String paramString2) { for (int i = 0; i < this.configs.length; i++) { Provider localProvider = getProvider(i); Provider.Service localService = localProvider.getService(paramString1, paramString2); if (localService != null) { return localService; } } return null; }
GetInstance.getServices其實是遍歷所有的Provider,然後按順序返回第一個有這個算法服務的Provide的算法服務(Provider.Service)。這裡可以看出,尋找服務需要兩個參數,第一個參數是type,比如"KeyGenerator",第二個是算法名稱,“AES”。那現在我們只要知道有哪些Provide,每個Provide裡有哪些Provider.Service就可以了。
在jdk的API中,查看 KeyGenerator.getInstance方法,其中給了我們提示:
我們可以本地寫一個方法遍歷jdk所有的算法:
package com.hongkang.test; import java.security.Provider; import java.security.Security; import java.security.Provider.Service; public class TestSecurity { public static void main(String[] args) { Provider[] providers = Security.getProviders(); for(Provider p:providers){ System.out.println("provider name:"+p.getName()); for(Service s:p.getServices()){ System.out.println("類型:"+s.getType()+",算法:"+s.getAlgorithm()); } System.out.println("--------------------------"); } } }
輸出結果:
provider name:SUN 類型:SecureRandom,算法:SHA1PRNG 類型:Signature,算法:SHA1withDSA 類型:Signature,算法:NONEwithDSA 類型:KeyPairGenerator,算法:DSA 類型:MessageDigest,算法:MD2 類型:MessageDigest,算法:MD5 類型:MessageDigest,算法:SHA 類型:MessageDigest,算法:SHA-256 類型:MessageDigest,算法:SHA-384 類型:MessageDigest,算法:SHA-512 類型:AlgorithmParameterGenerator,算法:DSA 類型:AlgorithmParameters,算法:DSA 類型:KeyFactory,算法:DSA 類型:CertificateFactory,算法:X.509 類型:KeyStore,算法:JKS 類型:KeyStore,算法:CaseExactJKS 類型:Policy,算法:JavaPolicy 類型:Configuration,算法:JavaLoginConfig 類型:CertPathBuilder,算法:PKIX 類型:CertPathValidator,算法:PKIX 類型:CertStore,算法:LDAP 類型:CertStore,算法:Collection 類型:CertStore,算法:com.sun.security.IndexedCollection -------------------------- provider name:SunRsaSign 類型:KeyFactory,算法:RSA 類型:KeyPairGenerator,算法:RSA 類型:Signature,算法:MD2withRSA 類型:Signature,算法:MD5withRSA 類型:Signature,算法:SHA1withRSA 類型:Signature,算法:SHA256withRSA 類型:Signature,算法:SHA384withRSA 類型:Signature,算法:SHA512withRSA -------------------------- provider name:SunEC 類型:KeyFactory,算法:EC 類型:AlgorithmParameters,算法:EC 類型:Signature,算法:NONEwithECDSA 類型:Signature,算法:SHA1withECDSA 類型:Signature,算法:SHA256withECDSA 類型:Signature,算法:SHA384withECDSA 類型:Signature,算法:SHA512withECDSA 類型:KeyPairGenerator,算法:EC 類型:KeyAgreement,算法:ECDH -------------------------- provider name:SunJSSE 類型:KeyFactory,算法:RSA 類型:KeyPairGenerator,算法:RSA 類型:Signature,算法:MD2withRSA 類型:Signature,算法:MD5withRSA 類型:Signature,算法:SHA1withRSA 類型:Signature,算法:MD5andSHA1withRSA 類型:KeyManagerFactory,算法:SunX509 類型:KeyManagerFactory,算法:NewSunX509 類型:TrustManagerFactory,算法:SunX509 類型:TrustManagerFactory,算法:PKIX 類型:SSLContext,算法:TLSv1 類型:SSLContext,算法:TLSv1.1 類型:SSLContext,算法:TLSv1.2 類型:SSLContext,算法:Default 類型:KeyStore,算法:PKCS12 -------------------------- provider name:SunJCE 類型:Cipher,算法:RSA 類型:Cipher,算法:DES 類型:Cipher,算法:DESede 類型:Cipher,算法:DESedeWrap 類型:Cipher,算法:PBEWithMD5AndDES 類型:Cipher,算法:PBEWithMD5AndTripleDES 類型:Cipher,算法:PBEWithSHA1AndRC2_40 類型:Cipher,算法:PBEWithSHA1AndDESede 類型:Cipher,算法:Blowfish 類型:Cipher,算法:AES 類型:Cipher,算法:AESWrap 類型:Cipher,算法:RC2 類型:Cipher,算法:ARCFOUR 類型:KeyGenerator,算法:DES 類型:KeyGenerator,算法:DESede 類型:KeyGenerator,算法:Blowfish 類型:KeyGenerator,算法:AES 類型:KeyGenerator,算法:RC2 類型:KeyGenerator,算法:ARCFOUR 類型:KeyGenerator,算法:HmacMD5 類型:KeyGenerator,算法:HmacSHA1 類型:KeyGenerator,算法:HmacSHA256 類型:KeyGenerator,算法:HmacSHA384 類型:KeyGenerator,算法:HmacSHA512 類型:KeyPairGenerator,算法:DiffieHellman 類型:AlgorithmParameterGenerator,算法:DiffieHellman 類型:KeyAgreement,算法:DiffieHellman 類型:AlgorithmParameters,算法:DiffieHellman 類型:AlgorithmParameters,算法:DES 類型:AlgorithmParameters,算法:DESede 類型:AlgorithmParameters,算法:PBE 類型:AlgorithmParameters,算法:PBEWithMD5AndDES 類型:AlgorithmParameters,算法:PBEWithMD5AndTripleDES 類型:AlgorithmParameters,算法:PBEWithSHA1AndDESede 類型:AlgorithmParameters,算法:PBEWithSHA1AndRC2_40 類型:AlgorithmParameters,算法:Blowfish 類型:AlgorithmParameters,算法:AES 類型:AlgorithmParameters,算法:RC2 類型:AlgorithmParameters,算法:OAEP 類型:KeyFactory,算法:DiffieHellman 類型:SecretKeyFactory,算法:DES 類型:SecretKeyFactory,算法:DESede 類型:SecretKeyFactory,算法:PBEWithMD5AndDES 類型:SecretKeyFactory,算法:PBEWithMD5AndTripleDES 類型:SecretKeyFactory,算法:PBEWithSHA1AndDESede 類型:SecretKeyFactory,算法:PBEWithSHA1AndRC2_40 類型:SecretKeyFactory,算法:PBKDF2WithHmacSHA1 類型:Mac,算法:HmacMD5 類型:Mac,算法:HmacSHA1 類型:Mac,算法:HmacSHA256 類型:Mac,算法:HmacSHA384 類型:Mac,算法:HmacSHA512 類型:Mac,算法:HmacPBESHA1 類型:Mac,算法:SslMacMD5 類型:Mac,算法:SslMacSHA1 類型:KeyStore,算法:JCEKS 類型:KeyGenerator,算法:SunTlsPrf 類型:KeyGenerator,算法:SunTls12Prf 類型:KeyGenerator,算法:SunTlsMasterSecret 類型:KeyGenerator,算法:SunTlsKeyMaterial 類型:KeyGenerator,算法:SunTlsRsaPremasterSecret -------------------------- provider name:SunJGSS 類型:GssApiMechanism,算法:1.2.840.113554.1.2.2 類型:GssApiMechanism,算法:1.3.6.1.5.5.2 -------------------------- provider name:SunSASL 類型:SaslClientFactory,算法:DIGEST-MD5 類型:SaslClientFactory,算法:NTLM 類型:SaslClientFactory,算法:GSSAPI 類型:SaslClientFactory,算法:EXTERNAL 類型:SaslClientFactory,算法:PLAIN 類型:SaslClientFactory,算法:CRAM-MD5 類型:SaslServerFactory,算法:CRAM-MD5 類型:SaslServerFactory,算法:GSSAPI 類型:SaslServerFactory,算法:DIGEST-MD5 類型:SaslServerFactory,算法:NTLM -------------------------- provider name:XMLDSig 類型:TransformService,算法:http://www.w3.org/2002/06/xmldsig-filter2 類型:TransformService,算法:http://www.w3.org/2000/09/xmldsig#enveloped-signature 類型:TransformService,算法:http://www.w3.org/2001/10/xml-exc-c14n#WithComments 類型:TransformService,算法:http://www.w3.org/2001/10/xml-exc-c14n# 類型:TransformService,算法:http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments 類型:XMLSignatureFactory,算法:DOM 類型:TransformService,算法:http://www.w3.org/2006/12/xml-c14n11 類型:TransformService,算法:http://www.w3.org/2000/09/xmldsig#base64 類型:TransformService,算法:http://www.w3.org/TR/2001/REC-xml-c14n-20010315 類型:TransformService,算法:http://www.w3.org/TR/1999/REC-xpath-19991116 類型:TransformService,算法:http://www.w3.org/TR/1999/REC-xslt-19991116 類型:TransformService,算法:http://www.w3.org/2006/12/xml-c14n11#WithComments 類型:KeyInfoFactory,算法:DOM -------------------------- provider name:SunPCSC 類型:TerminalFactory,算法:PC/SC -------------------------- provider name:SunMSCAPI 類型:SecureRandom,算法:Windows-PRNG 類型:KeyStore,算法:Windows-MY 類型:KeyStore,算法:Windows-ROOT 類型:Signature,算法:NONEwithRSA 類型:Signature,算法:SHA1withRSA 類型:Signature,算法:SHA256withRSA 類型:Signature,算法:SHA384withRSA 類型:Signature,算法:SHA512withRSA 類型:Signature,算法:MD5withRSA 類型:Signature,算法:MD2withRSA 類型:KeyPairGenerator,算法:RSA 類型:Cipher,算法:RSA 類型:Cipher,算法:RSA/ECB/PKCS1Padding --------------------------
通過觀察,我們發現算法的類型,基本都對應java的一個類。算法類基本在jce.jar和rt.jar中。從這個結果中我們基本就能自己找算法了,比如要用MD5,在上面列表中發現類型是MessageDigest,則
MessageDigest md5 = MessageDigest.getInstance("MD5");
再仔細查看java.security.Provider類源碼,發現此類在初始時就已經將這些算法類型初始化了,
static { addEngine("AlgorithmParameterGenerator", false, null); addEngine("AlgorithmParameters", false, null); addEngine("KeyFactory", false, null); addEngine("KeyPairGenerator", false, null); addEngine("KeyStore", false, null); addEngine("MessageDigest", false, null); addEngine("SecureRandom", false, null); addEngine("Signature", true, null); addEngine("CertificateFactory", false, null); addEngine("CertPathBuilder", false, null); addEngine("CertPathValidator", false, null); addEngine("CertStore", false, "java.security.cert.CertStoreParameters"); addEngine("Cipher", true, null); addEngine("ExemptionMechanism", false, null); addEngine("Mac", true, null); addEngine("KeyAgreement", true, null); addEngine("KeyGenerator", false, null); addEngine("SecretKeyFactory", false, null); addEngine("KeyManagerFactory", false, null); addEngine("SSLContext", false, null); addEngine("TrustManagerFactory", false, null); addEngine("GssApiMechanism", false, null); addEngine("SaslClientFactory", false, null); addEngine("SaslServerFactory", false, null); addEngine("Policy", false, "java.security.Policy$Parameters"); addEngine("Configuration", false, "javax.security.auth.login.Configuration$Parameters"); addEngine("XMLSignatureFactory", false, null); addEngine("KeyInfoFactory", false, null); addEngine("TransformService", false, null); addEngine("TerminalFactory", false, "java.lang.Object"); }
//還對大小寫做了容錯處理
private static void addEngine(String paramString1, boolean paramBoolean, String paramString2)
{
EngineDescription localEngineDescription = new EngineDescription(paramString1, paramBoolean, paramString2);
knownEngines.put(paramString1.toLowerCase(Locale.ENGLISH), localEngineDescription);
knownEngines.put(paramString1, localEngineDescription);
}
不過遺憾的是並沒有找到AES這類算法是怎麼初始化的。但是經測試,即便使用的不是大寫,或者上面列表中列出的標准寫法,也能正常獲取,比如:
KeyGenerator kgen = KeyGenerator.getInstance("aEs");
也能正常執行。