補充第11期作業:Long.fastUUID與UUID.toString之間的關系
阿新 • • 發佈:2018-09-03
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之間的關系