Skip to content

Instantly share code, notes, and snippets.

@relax-more
Created January 22, 2013 05:54
Show Gist options
  • Save relax-more/4592436 to your computer and use it in GitHub Desktop.
Save relax-more/4592436 to your computer and use it in GitHub Desktop.
SecureRandomがどの程度Secureなのかを確認した時のメモ
結論。
SecureRandomのインスタンスを生成する時に明示的にSeedを与えない場合は実行環境に関する下記のようなデータや
タイムスタンプをHashにしてseed としている。
System.getProperties()
InetAddress.getLocalHost().toString().getBytes()
File(p.getProperty("java.io.tmpdir"))
途中で例外が発生した場合はそのExceptionのByteCode
参考
■調査のための導入資料+TomcatでのSessionの実装から乱数生成を学ぶ
http://d.hatena.ne.jp/higher_tomorrow/searchdiary?word=%CD%F0%BF%F4
■javaのシステムプロパティとはなんぞや
http://www.ne.jp/asahi/hishidama/home/tech/java/application.html#version_system.property
// メモのため抜粋
// 乱数を生成する際に seed が登録されていない場合、SeedGenerator#getSystemEntropy
// でSeedの取得を行なっている
package sun.security.provider;
public final class SecureRandom extends SecureRandomSpi implements java.io.Serializable {
/**
* Generates a user-specified number of random bytes.
*
* @param bytes the array to be filled in with random bytes.
*/
public synchronized void engineNextBytes(byte[] result) {
int index = 0;
int todo;
byte[] output = remainder;
if (state == null) {
if (seeder == null) {
// 乱数を生成する際に seed が登録されていない場合、
seeder = new SecureRandom(SeedGenerator.getSystemEntropy());
seeder.engineSetSeed(engineGenerateSeed(DIGEST_SIZE));
}
byte[] seed = new byte[DIGEST_SIZE];
seeder.engineNextBytes(seed);
state = digest.digest(seed);
}
// Use remainder from last time
int r = remCount;
if (r > 0) {
// How many bytes?
todo = (result.length - index) < (DIGEST_SIZE - r) ?
(result.length - index) : (DIGEST_SIZE - r);
// Copy the bytes, zero the buffer
for (int i = 0; i < todo; i++) {
result[i] = output[r];
output[r++] = 0;
}
remCount += todo;
index += todo;
}
// If we need more bytes, make them.
while (index < result.length) {
// Step the state
digest.update(state);
output = digest.digest();
updateState(state, output);
// How many bytes?
todo = (result.length - index) > DIGEST_SIZE ?
DIGEST_SIZE : result.length - index;
// Copy the bytes, zero the buffer
for (int i = 0; i < todo; i++) {
result[index++] = output[i];
output[i] = 0;
}
remCount += todo;
}
// Store remainder for next time
remainder = output;
remCount %= DIGEST_SIZE;
}
}
// メモのため抜粋
// seedGenerator#getSystemEntropy では
// MessageDigestを下記の3つの値とRuntimeのメモリを利用して更新している
// System.getProperties()
// InetAddress.getLocalHost().toString().getBytes()
// File(p.getProperty("java.io.tmpdir"))
// また、途中で例外が発生した場合はそのExceptionのByteCodeで更新を行なっている
package sun.security.provider;
abstract class SeedGenerator{
static byte[] getSystemEntropy() {
byte[] ba;
final MessageDigest md;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException nsae) {
throw new InternalError("internal error: SHA-1 not available.");
}
// The current time in millis
byte b =(byte)System.currentTimeMillis();
md.update(b);
java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<Void>() {
public Void run() {
try {
// System properties can change from machine to machine
String s;
Properties p = System.getProperties();
Enumeration<?> e = p.propertyNames();
while (e.hasMoreElements()) {
s =(String)e.nextElement();
md.update(s.getBytes());
md.update(p.getProperty(s).getBytes());
}
md.update(InetAddress.getLocalHost().toString().getBytes());
// The temporary dir
File f = new File(p.getProperty("java.io.tmpdir"));
String[] sa = f.list();
for(int i = 0; i < sa.length; i++)
md.update(sa[i].getBytes());
} catch (Exception ex) {
md.update((byte)ex.hashCode());
}
// get Runtime memory stats
Runtime rt = Runtime.getRuntime();
byte[] memBytes = longToByteArray(rt.totalMemory());
md.update(memBytes, 0, memBytes.length);
memBytes = longToByteArray(rt.freeMemory());
md.update(memBytes, 0, memBytes.length);
return null;
}
});
return md.digest();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment