1. 程式人生 > >補充第11期作業:Long.fastUUID與UUID.toString之間的關系

補充第11期作業:Long.fastUUID與UUID.toString之間的關系

exc shell nts random exce 64 bit get() 封裝 ads

一 UUID.toString方法與Long.fastUUID方法的關聯

  • UUID類
public final class UUID implements java.io.Serializable, Comparable<UUID> {

     public static UUID randomUUID() {
        SecureRandom ng = Holder.numberGenerator;

        byte[] randomBytes = new byte[16];
        ng.nextBytes(randomBytes); // 真正生成隨機數的地方
        randomBytes[6]  &= 0x0f;  /* clear version        */
        randomBytes[6]  |= 0x40;  /* set to version 4     */
        randomBytes[8]  &= 0x3f;  /* clear variant        */
        randomBytes[8]  |= 0x80;  /* set to IETF variant  */
        return new UUID(randomBytes);
    }

    /*
     * The random number generator used by this class to create random
     * based UUIDs. In a holder class to defer initialization until needed.
     */
    private static class Holder {
        static final SecureRandom numberGenerator = new SecureRandom();
    }
    
    /*
     * The most significant 64 bits of this UUID.
     * @serial
     */
    private final long mostSigBits;

    /*
     * The least significant 64 bits of this UUID.
     * @serial
     */
    private final long leastSigBits;
    
    private UUID(byte[] data) {
        long msb = 0;
        long lsb = 0;
        assert data.length == 16 : "data must be 16 bytes in length";
        // long的64位:    8位    8位 8位 8位 8位 8位 8位 8位   8位
        // 簡單說:msb = data[0]     ......      ......       data[7]
        for (int i=0; i<8; i++)
            msb = (msb << 8) | (data[i] & 0xff); 
        // long的64位:    8位    8位 8位 8位 8位 8位 8位 8位   8位
        // 簡單說:lsb = data[8]     ......      ......       data[15]
        for (int i=8; i<16; i++)
            lsb = (lsb << 8) | (data[i] & 0xff);
        this.mostSigBits = msb;
        this.leastSigBits = lsb;
    }
    
    // SharedSecrets javaLangAccess變量什麽時候設置進去?
    // 答案是System
    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
    
    public String toString() {
        return jla.fastUUID(leastSigBits, mostSigBits);// 實際調用了Long.fastUUID方法
    }
}

public final class System {
    /**
     * Initialize the system class.  Called after thread initialization.
     */
    private static void initPhase1() {
        // ...
        setJavaLangAccess();
        // ...
    }
    
    private static void setJavaLangAccess() {
        // Allow privileged classes outside of java.lang
        // 匿名內部類註冊
        SharedSecrets.setJavaLangAccess(new JavaLangAccess() {
            // ......
            public String fastUUID(long lsb, long msb) {
                return Long.fastUUID(lsb, msb);
            }
        });
    }
}

public final class Long extends Number implements Comparable<Long> {
    
    // 其實就是提供UUID的toString方法.......
    static String fastUUID(long lsb, long msb) {
        if (COMPACT_STRINGS) {
            byte[] buf = new byte[36];
            formatUnsignedLong0(lsb,        4, buf, 24, 12);
            formatUnsignedLong0(lsb >>> 48, 4, buf, 19, 4);
            formatUnsignedLong0(msb,        4, buf, 14, 4);
            formatUnsignedLong0(msb >>> 16, 4, buf, 9,  4);
            formatUnsignedLong0(msb >>> 32, 4, buf, 0,  8);

            buf[23] = ‘-‘;
            buf[18] = ‘-‘;
            buf[13] = ‘-‘;
            buf[8]  = ‘-‘;

            return new String(buf, LATIN1);
        } else {
            byte[] buf = new byte[72];

            formatUnsignedLong0UTF16(lsb,        4, buf, 24, 12);
            formatUnsignedLong0UTF16(lsb >>> 48, 4, buf, 19, 4);
            formatUnsignedLong0UTF16(msb,        4, buf, 14, 4);
            formatUnsignedLong0UTF16(msb >>> 16, 4, buf, 9,  4);
            formatUnsignedLong0UTF16(msb >>> 32, 4, buf, 0,  8);

            StringUTF16.putChar(buf, 23, ‘-‘);
            StringUTF16.putChar(buf, 18, ‘-‘);
            StringUTF16.putChar(buf, 13, ‘-‘);
            StringUTF16.putChar(buf,  8, ‘-‘);

            return new String(buf, UTF16);
        }
    }
}
  • UUID的組成部分

參考:http://www.ietf.org/rfc/rfc4122.txt

UUID  = time-low "-" time-mid "-" time-high-and-version "-" clock-seq-and-reserved clock-seq-low "-" node
time-low               = 4hexOctet
time-mid               = 2hexOctet
time-high-and-version  = 2hexOctet
clock-seq-and-reserved = hexOctet
clock-seq-low          = hexOctet
node                   = 6hexOctet
hexOctet               = hexDigit hexDigit
hexDigit =
"0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" /
"a" / "b" / "c" / "d" / "e" / "f" /
"A" / "B" / "C" / "D" / "E" / "F"

二 Java加密體系結構(JCA)

參考:https://blog.csdn.net/u012741741/article/details/79209984

這篇譯文很好,不過本文不是為了講解加密體系,所以盡量只獲取最少的額外知識點來完成UUID.randomUUID的剖析

1 介紹

  • JAVA平臺強調安全性,包含內容很多如:語言安全,密碼學,公鑰基礎設施,認證,安全通信和訪問控制。
  • JCA是JAVA平臺的一部分,提供一個“Provider”體系結構和一組用於數字簽名,消息摘要(哈希),證書和證書驗證,加密(對稱/非對稱塊/流密碼),密鑰生成管理和安全隨機數生成等等。有了這些API,開發人員可以輕松將安全性集成到自己的應用中。
  • JCA設計原則:
    • 實現獨立性:應用程序不需要自己實現安全性,它們可以從Java平臺請求安全服務。
    • 實現互操作性:Provider不需要綁定到固定的應用中,應用也不需要綁定特定的Provider
    • 算法可拓展性: Java平臺包含許多內置的Provider,這些Provider實現了當今廣泛使用的一組基本的安全服務 。但也許有些應用希望集成新興的算法

2 UUID中涉及JCA的類

  • SecureRandom:它是一個隨機數生成器(RNG),同時是JCA中的其中一個引擎類。引擎類為特定類型的密碼服務提供接口,而不依賴於特定的密碼算法或提供者。
  • SecureRandomSpi:該類定義了SecureRandom的服務提供者接口(SPI),意味著為SecureRandom提供具體實現的生成器需要實現該類的所有方法。
  • DRBG:它實現了"SecureRandom.DRBG"算法,是SecureRandom的其中一個隨機數生成器實現。
  • Provider:該類表示Java安全API的“提供者”,其中某個具體提供者需要實現Java安全的部分或全部部分。
  • Sun:Sun的安全提供者,Provider的子類。
  • Provider.Service:Provider的內部類,封裝SPI的具體實現類,通過Service能夠找到具體的實現類

3 SecureRandom的具體實現類追尋

(1)找出Jdk中有許多Providers,許多官方的,或者第三方添加。如:Sun、SunJCE、JdkLDAP、XMLLDSig等

(2)順序遍歷Providers並解析Providers中提供的算法為Services,如:

  • SecureRandom.DRBG -> sun.security.provider.DRBG
  • MessageDigest.SHA -> sun.security.provider.SHA
  • Alg.Alias.KeyPairGenerator.1.2.8400.10040.4.1 -> DSA
  • Alg.Alias.CertificateFactory.X509 -> X.509
  • Provider.id info -> SUN(DSA key/parameter generation; DSA signing; SHA-1 , MD5...)
  • .....

(3)發現DRBG是SecureRandom的具體提供者

(4)根據DRBG的全類名創建對象並返回使用

4 通過代碼跟蹤看看

public class SecureRandom extends java.util.Random {
    
    public SecureRandom() {
        super(0);
        getDefaultPRNG(false, null);
        this.threadSafe = getThreadSafe();
   }
    
   private void getDefaultPRNG(boolean setSeed, byte[] seed) {
        String prng = getPrngAlgorithm(); // 返回"DRBG"
        if (prng == null) {
            prng = "SHA1PRNG";
            this.secureRandomSpi = new sun.security.provider.SecureRandom();
            this.provider = Providers.getSunProvider();
            if (setSeed) this.secureRandomSpi.engineSetSeed(seed);
        } else { 
            try {
                SecureRandom random = SecureRandom.getInstance(prng);
                this.secureRandomSpi = random.getSecureRandomSpi();
                this.provider = random.getProvider();
                if (setSeed) {
                    this.secureRandomSpi.engineSetSeed(seed);
                }
            } catch (NoSuchAlgorithmException nsae) {
                throw new RuntimeException(nsae);
            }
        }
        if (getClass() == SecureRandom.class) {
            this.algorithm = prng;
        }
    }
    
    private static String getPrngAlgorithm() {
        for (Provider p : Providers.getProviderList().providers()) {
            for (Service s : p.getServices()) {
                if (s.getType().equals("SecureRandom"))  return s.getAlgorithm();
            }
        }
        return null;
    }
    
   public static SecureRandom getInstance(String algorithm) throws NoSuchAlgorithmException {
        Instance instance = GetInstance.getInstance("SecureRandom",
                                                    SecureRandomSpi.class,
                                                    algorithm);
        return new SecureRandom((SecureRandomSpi)instance.impl,
                                instance.provider, algorithm);
    }
}

public class GetInstance {
    public static Instance getInstance(String type, Class<?> clazz,
            String algorithm) throws NoSuchAlgorithmException {
        ProviderList list = Providers.getProviderList();
        Service firstService = list.getService(type, algorithm);
        return getInstance(firstService, clazz);
    }
    
     public static Instance getInstance(Service s, Class<?> clazz)
            throws NoSuchAlgorithmException {
        Object instance = s.newInstance(null);
        return new Instance(s.getProvider(), instance);
    }
}

public class Provider{
    
    public class Service{
        public Object newInstance(Object constructorParameter)
                throws NoSuchAlgorithmException {
            Class<?> ctrParamClz;
            EngineDescription cap = knownEngines.get(type);
            if (cap == null) {
                ctrParamClz = constructorParameter == null?
                    null : constructorParameter.getClass();
            } else {
                ctrParamClz = cap.constructorParameterClassName == null?
                    null : Class.forName(cap.constructorParameterClassName);
            }
            return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter);
        }
        
        // 返回class sun.security.provider.DRBG
        // return the implementation Class object for this service
        private Class<?> getImplClass() throws NoSuchAlgorithmException {
            Reference<Class<?>> ref = classRef;
            Class<?> clazz = (ref == null) ? null : ref.get();
            ClassLoader cl = provider.getClass().getClassLoader();
            if (cl == null) {
                clazz = Class.forName(className);//className為sun.security.provider.DRBG
            } else {
                clazz = cl.loadClass(className);
            }
            classRef = new WeakReference<>(clazz);
            return clazz;
        }
    }
    
     private static Object newInstanceUtil(final Class<?> clazz,
        final Class<?> ctrParamClz, final Object ctorParamObj)
        throws Exception {
        if (ctrParamClz == null) {
            Constructor<?> con = clazz.getConstructor();
            // 最後就是構造器的newInstance
            return con.newInstance();
        } else {
            Constructor<?> con = clazz.getConstructor(ctrParamClz);
            return con.newInstance(ctorParamObj);
        }
    }
}

補充第11期作業:Long.fastUUID與UUID.toString之間的關系