java 安全體系算法調(diào)用過程

java 安全體系主要分為

  • JCA(Java Cryptography Architectrue)java加密體系
  • JCE(Java Cryptography Extension)java加密拓展
  • JSSE (Java Secure Socket Extesion)java套接字安全拓展
  • JAAS(Java Authentication and Authentication Service)Java驗證和授權(quán)API

它們并不執(zhí)行各種算法,只是連接應(yīng)用和實際算法實現(xiàn)程序的一組接口。軟件開發(fā)商根據(jù)JCE接口,將各種算法實現(xiàn)后,打包成一個Provider,可以動態(tài)地加到Java運行環(huán)境中

Android Provider 當(dāng)中默認(rèn)包含的算法類型

        // JCA
        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");
        // JCE
        addEngine("Cipher",                             true,  null);
        addEngine("ExemptionMechanism",                 false, null);
        addEngine("Mac",                                true,  null);
        addEngine("KeyAgreement",                       true,  null);
        addEngine("KeyGenerator",                       false, null);
        addEngine("SecretKeyFactory",                   false, null);
        // JSSE
        addEngine("KeyManagerFactory",                  false, null);
        addEngine("SSLContext",                         false, null);
        addEngine("TrustManagerFactory",                false, null);
        // JGSS
        addEngine("GssApiMechanism",                    false, null);
        // SASL
        addEngine("SaslClientFactory",                  false, null);
        addEngine("SaslServerFactory",                  false, null);
        // POLICY
        addEngine("Policy",                             false,
                            "java.security.Policy$Parameters");
        // CONFIGURATION
        addEngine("Configuration",                      false,
                            "javax.security.auth.login.Configuration$Parameters");
        // XML DSig
        addEngine("XMLSignatureFactory",                false, null);
        addEngine("KeyInfoFactory",                     false, null);
        addEngine("TransformService",                   false, null);
        // Smart Card I/O
        addEngine("TerminalFactory",                    false,
                            "java.lang.Object");

Java 安全體系擴(kuò)展性很強(qiáng),除了 jdk 提供的算法實現(xiàn)外 可以使用第三方j(luò)ava拓展,常用安全供應(yīng)者的有

  1. Bouncy Castle
  2. Commons Codec – Apache

如何配置添加第三方的安全供應(yīng)者

方法 1 .配置文件

Mac 桌面系統(tǒng)配置擴(kuò)展 provider ,并沒有加入 Bouncy Castle

配置文件在 jdk安裝目錄的 jre/lib/security/java.security


1.png

Android 系統(tǒng)配置在 security.properties


2.png

Android 默認(rèn)配置了 BouncyCastleProvider ,但是閹割版的,BouncyCastleProvider 類中有的,但是 Android 上不一定會有.
3.png
  1. 代碼動態(tài)添加
Security.addProvider(new BouncyCastleProvider());

(Android 手機(jī)可能不會生效,因為 Android 已經(jīng)默認(rèn)添加過閹割版本的 可以先移除系統(tǒng)自帶的再添加,不過部分手機(jī)仍然不會生效);

最穩(wěn)妥的辦法就是 當(dāng)使用到某種算法的時候就直接傳入一個 Provider 對象,就會使用到我們擴(kuò)展的安全供應(yīng)者的算法

Signature signature = Signature.getInstance("SM3withSM2", new BouncyCastleProvider());

Android 默認(rèn)配置的 Provider 初始化過程

在 java.security.Security 類當(dāng)中有一段靜態(tài)代碼塊去加載 security.properties 文件,就會把security.properties 的配置的屬性加載進(jìn)來到 props 對象

   static {
        props = new Properties();
        InputStream is = null;
        InputStream propStream = Security.class.getResourceAsStream("security.properties");
         is  = new BufferedInputStream(propStream);
         props.load(is);
    }

在 java.security.Provider.Providers類中的靜態(tài)代碼塊中

 static {
        // set providerList to empty list first in case initialization somehow
        // triggers a getInstance() call (although that should not happen)
        providerList = ProviderList.EMPTY;
        // 1. 新建一個 ProviderList 對象
        providerList = ProviderList.fromSecurityProperties(); 

        // removeInvalid is specified to try initializing all configured providers
        // and removing those that aren't instantiable. This has the side effect
        // of eagerly initializing all providers.
        final int numConfiguredProviders = providerList.size();
        // 2.初始化并移除那些無法初始化的各個 Provider 
        providerList = providerList.removeInvalid();
        if (numConfiguredProviders != providerList.size()) {
            throw new AssertionError("Unable to configure default providers");
        }
    }

fromSecurityProperties 方法中會 new ProviderList();對象

在 sun.security.jca.ProviderList
讀取 props 對象保存的security.properties
中security.provider 獲取類名和參數(shù)構(gòu)建 ProviderConfig對象

  /**
     * Return a new ProviderList parsed from the java.security Properties.
     */
    private ProviderList() {
        List<ProviderConfig> configList = new ArrayList<>();
        for (int i = 1; true; i++) {
            String entry = Security.getProperty("security.provider." + i);
            if (entry == null) {
                break;
            }
            entry = entry.trim();
            if (entry.length() == 0) {
                System.err.println("invalid entry for " +
                                   "security.provider." + i);
                break;
            }
            int k = entry.indexOf(' ');
            ProviderConfig config;
            if (k == -1) {
                config = new ProviderConfig(entry);
            } else {
                String className = entry.substring(0, k);
                String argument = entry.substring(k + 1).trim();
                config = new ProviderConfig(className, argument);
            }

            // Get rid of duplicate providers.
            if (configList.contains(config) == false) {
                configList.add(config);
            }
        }
    }

這個就拿到了配置的 provider 的類名 構(gòu)建 ProviderConfig對象 并且存儲在 ProviderConfig[] configs;數(shù)組當(dāng)中

    /**
     * Try to load all Providers and return the ProviderList. If one or
     * more Providers could not be loaded, a new ProviderList with those
     * entries removed is returned. Otherwise, the method returns this.
     */
    ProviderList removeInvalid() {
        int n = loadAll();
        if (n == configs.length) {
            return this;
        }
        ProviderConfig[] newConfigs = new ProviderConfig[n];
        for (int i = 0, j = 0; i < configs.length; i++) {
            ProviderConfig config = configs[i];
            if (config.isLoaded()) {
                newConfigs[j++] = config;
            }
        }
        return new ProviderList(newConfigs, true);
    }

調(diào)用 loadAll 方法

    // attempt to load all Providers not already loaded
    private int loadAll() {
        int n = 0;
        for (int i = 0; i < configs.length; i++) {
            Provider p = configs[i].getProvider();
            if (p != null) {
                n++;
            }
        }
        if (n == configs.length) {
            allLoaded = true;
        }
        return n;
    }

調(diào)用各個 ProviderConfig對象的 getProvider方法

    /**
     * Get the provider object. Loads the provider if it is not already loaded.
     */
    synchronized Provider getProvider() {
        // volatile variable load
        Provider p = provider;
        if (p != null) {
            return p;
        }
        if (shouldLoad() == false) {
            return null;
        }
        if (isLoading) {
            return null;
        }
        try {
            isLoading = true;
            tries++;
            p = doLoadProvider();
        } finally {
            isLoading = false;
        }
        provider = p;
        return p;
    }

調(diào)用 doLoadProvider 方法

    private Provider doLoadProvider() {
         return initProvider(className, Object.class.getClassLoader());
    }

調(diào)用 initProvider 通過反射調(diào)用構(gòu)造函數(shù)獲取 Provider 對象

    private Provider initProvider(String className, ClassLoader cl) throws Exception {
        Class<?> provClass;
        if (cl != null) {
            provClass = cl.loadClass(className);
        } else {
            provClass = Class.forName(className);
        }
        Object obj;
        if (hasArgument() == false) {
            obj = provClass.newInstance();
        } else {
            Constructor<?> cons = provClass.getConstructor(CL_STRING);
            obj = cons.newInstance(argument);
        }
        if (obj instanceof Provider) {
            return (Provider)obj;
        } else {
            disableLoad();
            return null;
        }
    }

然后 配置的 Provider 類就會加載進(jìn)來并且創(chuàng)建對象.現(xiàn)在已將 BouncyCastleProvider 配置進(jìn)來了

舉例說明 MD5 算法是如何被加載進(jìn)來被使用的 ,其他的也類似.

BouncyCastleProvider 的構(gòu)造函數(shù) 調(diào)用父類的構(gòu)造函數(shù) PROVIDER_NAME ,這個是一個 key ,每個 Provider 通過這個參數(shù)也能夠找到相應(yīng)的 Provider 對象 .

public static final String PROVIDER_NAME = "BC";
  /**
     * Construct a new provider.  This should only be required when
     * using runtime registration of the provider using the
     * <code>Security.addProvider()</code> mechanism.
     */
    public BouncyCastleProvider()
    {
        super(PROVIDER_NAME, 1.56, info);
         setup();
    }

然后調(diào)用 setup方法

    /*
     * Configurable digests
     */
    private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest.";
    private static final String[] DIGESTS =
    {
        // BEGIN android-removed
        // "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224",
        // "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b"
        // END android-removed
        // BEGIN android-added
        "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512",
        // END android-added
    };
    
    private void setup()
    {
        loadAlgorithms(DIGEST_PACKAGE, DIGESTS);
    }

調(diào)用 loadAlgorithms ,通過 for 循環(huán)加載反射拿到相應(yīng)的類對象 如 MD5算法
就會加載 org.bouncycastle.jcajce.provider.digest.MD5$Mappings 這個類(org.bouncycastle.jcajce.provider.digest.MD5的靜態(tài)內(nèi)部類)
并且創(chuàng)建對象調(diào)用 configure方法

    private void loadAlgorithms(String packageName, String[] names)
    {
        for (int i = 0; i != names.length; i++)
        {
            Class clazz = null;
            try
            {
                ClassLoader loader = this.getClass().getClassLoader();

                if (loader != null)
                {
                    clazz = loader.loadClass(packageName + names[i] + "$Mappings");
                }
                else
                {
                    clazz = Class.forName(packageName + names[i] + "$Mappings");
                }
            }
            catch (ClassNotFoundException e)
            {
                // ignore
            }

            if (clazz != null)
            {
                try
                {
                    ((AlgorithmProvider)clazz.newInstance()).configure(this);
                }
                catch (Exception e)
                {   // this should never ever happen!!
                    throw new InternalError("cannot create instance of "
                        + packageName + names[i] + "$Mappings : " + e);
                }
            }
        }
    }

在 org.bouncycastle.jcajce.provider.digest.MD5類中

package org.bouncycastle.jcajce.provider.digest;

public class MD5
{
    private MD5()
    {
    }
    /**
     * MD5 HashMac
     */
    public static class HashMac
        extends BaseMac
    {
        public HashMac()
        {
            super(new HMac(new MD5Digest()));
        }
    }

    public static class KeyGenerator
        extends BaseKeyGenerator
    {
        public KeyGenerator()
        {
            super("HMACMD5", 128, new CipherKeyGenerator());
        }
    }

    static public class Digest
        extends BCMessageDigest
        implements Cloneable
    {
        public Digest()
        {
            super(new MD5Digest());
        }

        public Object clone()
            throws CloneNotSupportedException
        {
            Digest d = (Digest)super.clone();
            d.digest = new MD5Digest((MD5Digest)digest);

            return d;
        }
    }

    public static class Mappings
        extends DigestAlgorithmProvider
    {
        private static final String PREFIX = MD5.class.getName();

        public Mappings()
        {
        }

        public void configure(ConfigurableProvider provider)
        {
            provider.addAlgorithm("MessageDigest.MD5", PREFIX + "$Digest");
            provider.addAlgorithm("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");

            addHMACAlgorithm(provider, "MD5", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
            addHMACAlias(provider, "MD5", IANAObjectIdentifiers.hmacMD5);
        }
    }
}

configure 方法調(diào)用 BouncyCastleProvider的 addAlgorithm

provider.addAlgorithm("MessageDigest.MD5", PREFIX + "$Digest");
provider.addAlgorithm("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");

PKCSObjectIdentifiers.md5 == "1.2.840.113549.2.5"

BouncyCastleProvider的 addAlgorithm調(diào)用了 put方法 ,put 是父類 Provider的方法

    public void addAlgorithm(String key, String value)
    {
        if (containsKey(key))
        {
            throw new IllegalStateException("duplicate provider key (" + key + ") found");
        }

        put(key, value);
    }

Provider的put 方法調(diào)用 implPut

    @Override
    public synchronized Object put(Object key, Object value) {
        check("putProviderProperty."+name);
        return implPut(key, value);
    }

implPut 就會把
字符串 key "MessageDigest.MD5",和 value 類名 org.bouncycastle.jcajce.provider.digest.MD5$Digest

key "Alg.Alias.MessageDigest.1.2.840.113549.2.5" 和 value "MD5"

存入legacyStrings Map 當(dāng)中

    private transient Map<String,String> legacyStrings;
    
    private Object implPut(Object key, Object value) {
        if ((key instanceof String) && (value instanceof String)) {
            if (!checkLegacy(key)) {
                return null;
            }
            legacyStrings.put((String)key, (String)value);
        }
        return super.put(key, value);
    }

如何使用 BouncyCastleProvider 的 MD5 方法

MessageDigest md = MessageDigest.getInstance("MD5",new BouncyCastleProvider());

MessageDigest .getInstance 參數(shù)分別為 ("MD5",BouncyCastleProvider對象)

    public static MessageDigest getInstance(String algorithm,
                                            Provider provider)
        throws NoSuchAlgorithmException
    {
        if (provider == null)
            throw new IllegalArgumentException("missing provider");
        Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
        if (objs[0] instanceof MessageDigest) {
            MessageDigest md = (MessageDigest)objs[0];
            md.provider = (Provider)objs[1];
            return md;
        } else {
            MessageDigest delegate =
                new Delegate((MessageDigestSpi)objs[0], algorithm);
            delegate.provider = (Provider)objs[1];
            return delegate;
        }
    }

調(diào)用 Security 的 getImpl ("MD5","MessageDigest",BouncyCastleProvider對象)

    static Object[] getImpl(String algorithm, String type, Provider provider)
            throws NoSuchAlgorithmException {
        return GetInstance.getInstance
            (type, getSpiClass(type), algorithm, provider).toArray();
    }

調(diào)用GetInstance類的 getSpiClass 方法

加載 java.security.MessageDigestSpi 類并把它加入到 spiMap 緩存起來方便下次使用

    private static Class<?> getSpiClass(String type) {
        Class<?> clazz = spiMap.get(type);
        if (clazz != null) {
            return clazz;
        }
        try {
            clazz = Class.forName("java.security." + type + "Spi");
            spiMap.put(type, clazz);
            return clazz;
        } catch (ClassNotFoundException e) {
            throw new AssertionError("Spi class not found", e);
        }
    }

GetInstance類 getInstance ("MessageDigest",MessageDigestSpi.class,"MD5",BouncyCastleProvider對象)

    public static Instance getInstance(String type, Class<?> clazz,
            String algorithm, Provider provider)
            throws NoSuchAlgorithmException {
        return getInstance(getService(type, algorithm, provider), clazz);
    }

GetInstance類 getService ("MessageDigest","MD5",BouncyCastleProvider對象)

    public static Service getService(String type, String algorithm,
            Provider provider) throws NoSuchAlgorithmException {
        Service s = provider.getService(type, algorithm);
        return s;
    }

調(diào)用 BouncyCastleProvider 父類的Provider getService ("MessageDigest","MD5")

    public synchronized Service getService(String type, String algorithm) {

        ServiceKey key = previousKey;
        if (key.matches(type, algorithm) == false) {
            key = new ServiceKey(type, algorithm, false);
            previousKey = key;
        }
        ensureLegacyParsed();
        return (legacyMap != null) ? legacyMap.get(key) : null;
    }

調(diào)用 Provider 的ensureLegacyParsed 方法

在之前分析 BouncyCastleProvider 對象在初始化的過程中已經(jīng)把字符串
key "MessageDigest.MD5",和 value 類名 org.bouncycastle.jcajce.provider.digest.MD5$Digest
key "Alg.Alias.MessageDigest.1.2.840.113549.2.5" 和 value "MD5"
存入legacyStrings 的Map 當(dāng)中 ,在 ensureLegacyParsed方法 for 循環(huán)取出調(diào)用 parseLegacyPut

    private void ensureLegacyParsed() {
        for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
            parseLegacyPut(entry.getKey(), entry.getValue());
        }
        removeInvalidServices(legacyMap);
        legacyChanged = false;
    }

調(diào)用 Provider 的 parseLegacyPut ("MessageDigest.MD5","org.bouncycastle.jcajce.provider.digest.MD5$Digest");方法 解析 生成key 為 ServiceKey對象,Value 為 Provider.Service,放入 legacyMap當(dāng)中

ServiceKey
    .type ="MessageDigest"
    .originalAlgorithm = "MD5"
    .algorithm = "MD5"

Provider.Service 
    .provider 屬性為BouncyCastleProvider對象
    .type = "MessageDigest";
    .algorithm = "MD5"
    .className = "org.bouncycastle.jcajce.provider.digest.MD5$Digest"

并為 Provider.Service 添加 aliases; 1.2.840.113549.2.5,

    private transient Map<ServiceKey,Service> legacyMap;
    
    private final static String ALIAS_PREFIX = "Alg.Alias.";
    private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
    private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();

    private void parseLegacyPut(String name, String value) {
        if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
            // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
            // aliasKey ~ MessageDigest.SHA
            String stdAlg = value;
            String aliasKey = name.substring(ALIAS_LENGTH);
            String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
            if (typeAndAlg == null) {
                return;
            }
            String type = getEngineName(typeAndAlg[0]);
            String aliasAlg = typeAndAlg[1].intern();
            ServiceKey key = new ServiceKey(type, stdAlg, true);
            Service s = legacyMap.get(key);
            if (s == null) {
                s = new Service(this);
                s.type = type;
                s.algorithm = stdAlg;
                legacyMap.put(key, s);
            }
            legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
            s.addAlias(aliasAlg);
        } else {
            String[] typeAndAlg = getTypeAndAlgorithm(name);
            if (typeAndAlg == null) {
                return;
            }
            int i = typeAndAlg[1].indexOf(' ');
            if (i == -1) {
                // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
                String type = getEngineName(typeAndAlg[0]);
                String stdAlg = typeAndAlg[1].intern();
                String className = value;
                ServiceKey key = new ServiceKey(type, stdAlg, true);
                Service s = legacyMap.get(key);
                if (s == null) {
                    s = new Service(this);
                    s.type = type;
                    s.algorithm = stdAlg;
                    legacyMap.put(key, s);
                }
                s.className = className;
            } else { // attribute
                // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
                String attributeValue = value;
                String type = getEngineName(typeAndAlg[0]);
                String attributeString = typeAndAlg[1];
                String stdAlg = attributeString.substring(0, i).intern();
                String attributeName = attributeString.substring(i + 1);
                // kill additional spaces
                while (attributeName.startsWith(" ")) {
                    attributeName = attributeName.substring(1);
                }
                attributeName = attributeName.intern();
                ServiceKey key = new ServiceKey(type, stdAlg, true);
                Service s = legacyMap.get(key);
                if (s == null) {
                    s = new Service(this);
                    s.type = type;
                    s.algorithm = stdAlg;
                    legacyMap.put(key, s);
                }
                s.addAttribute(attributeName, attributeValue);
            }
        }
    }

GetInstance類 getInstance (Provider.Service 對象,MessageDigestSpi.class)

    public static Instance getInstance(Service s, Class<?> clazz)
            throws NoSuchAlgorithmException {
        Object instance = s.newInstance(null);
        checkSuperClass(s, instance.getClass(), clazz);
        return new Instance(s.getProvider(), instance);
    }

調(diào)用 Provider.Service newInstance方法,會加載 org.bouncycastle.jcajce.provider.digest.MD5$Digest 類并反射生成對象賦值給 instance

Provider.Service 
    .provider 屬性為BouncyCastleProvider對象
    .type = "MessageDigest";
    .algorithm = "MD5"
    .className = "org.bouncycastle.jcajce.provider.digest.MD5$Digest"

然后調(diào)用 GetInstance 靜態(tài)內(nèi)部類GetInstance.Instance 的構(gòu)造函數(shù)(BouncyCastleProvider對象,instance)

    /**
     * Static inner class representing a newly created instance.
     */
    public static final class Instance {
        // public final fields, access directly without accessors
        public final Provider provider;
        public final Object impl;
        private Instance(Provider provider, Object impl) {
            this.provider = provider;
            this.impl = impl;
        }
        // Return Provider and implementation as an array as used in the
        // old Security.getImpl() methods.
        public Object[] toArray() {
            return new Object[] {impl, provider};
        }
    }

返回的 toArray 返回一個數(shù)組
最后
MessageDigest md = MessageDigest.getInstance("MD5",new BouncyCastleProvider());
中返回的就是 MessageDigest md = (MessageDigest)objs[0];
objs[0]就是 org.bouncycastle.jcajce.provider.digest.MD5$Digest 對象.以后使用這個對象執(zhí)行 MD5 的算法

這樣我們就通過添加 Provider 擴(kuò)展了 Java 體系的算法

經(jīng)過以上的分析,我們就可以自己自定義 Provider 擴(kuò)展的Java 的安全體系的算法

我們并不真的去實現(xiàn) MD5 算法,只是測試我們的 Provider 是否添加成功,自己寫的MD5算法是否被調(diào)用

自定義 Provider 擴(kuò)展的Java 的安全體系的算法

  1. 創(chuàng)建一個類繼承 Provider ,調(diào)用父類的構(gòu)造函數(shù)
public class MyProvider extends Provider {
    /**
     * Constructs a provider with the specified name, version number,
     * and information.
     *
     * @param name    the provider name.
     * @param version the provider version number.
     * @param info    a description of the provider and its services.
     */
    protected MyProvider(String name, double version, String info) {
        super(name, version, info);
    }

    public static final String PROVIDER_NAME = "com.example.MyProvider";

    MyProvider(){
        this(PROVIDER_NAME,1.4,"com.example.MyProvider info_version v1.4");
        init();
    }

    private void init() {
        put("MessageDigest.MD5","com.example.MyMessageDigest5");
    }
}
  1. 創(chuàng)建 com.example.MyMessageDigest5 類 這個類必須是 MessageDigestSpi的實現(xiàn)類

MessageDigest 繼承了 MessageDigestSpi ,最后 engineDigest()方法就是 md5 的計算結(jié)果

public class MyMessageDigest5 extends MessageDigest {

    public MyMessageDigest5() {
        super("MD5");
    }

    protected void engineUpdate(byte input) {

    }

    protected void engineUpdate(byte[] input, int offset, int len) {

    }

    protected byte[] engineDigest() {
        return "MyMessageDigest5 hello".getBytes();
    }

    protected void engineReset() {

    }
}
  1. 使用 MyProvider ,有兩種使用方式一種是直接傳入Provider對象,一種是用 Security.addProvider 接口添加再用 Provider的名字訪問
    private static String src = "hello provider";

    public static void main(String argv[]) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5", new MyProvider());
            byte[] md5Bytes = md.digest(src.getBytes());
            System.out.println(new String(md5Bytes));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        
        try {

            Security.addProvider(new MyProvider());
            MessageDigest md = MessageDigest.getInstance("MD5", MyProvider.PROVIDER_NAME);
            byte[] md5Bytes = md.digest(src.getBytes());
            System.out.println(new String(md5Bytes));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }

    }

最后的輸出結(jié)果,證明我們的 Provider 已添加,MD5算法 已被調(diào)用

ProviderTest.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容