240 likes | 415 Views
JAVA Cryptography. 4 장 Random Number 프로그래밍 언어 실험실 석사 3 학기 박중기. 목차. SecureRandom Self-Seeding Keyboard Timing SeederDialog. Random Number. pseudo-random number: 필연적으로 주기성이 발생하는 난수 PRNG : pseudo-random number generator seed : 의사 - 난수를 발생시킬 때의 초기값. SecureRandom.
E N D
JAVA Cryptography 4장 Random Number 프로그래밍 언어 실험실 석사 3학기 박중기
목차 • SecureRandom • Self-Seeding • Keyboard Timing • SeederDialog
Random Number • pseudo-random number: 필연적으로 주기성이 발생하는 난수 • PRNG : pseudo-random number generator • seed : 의사-난수를 발생시킬 때의 초기값
SecureRandom • java.util.Random에 PRNG가 구현되어있음 • 결점 • 예상할 수 있는 순서의 숫자를 생성하는 알고리즘 사용 • 시드값이 랜덤하지 않으면, 시스템 클럭을 이용하고, 이는 예상 가능한 시드이다.
SecureRandom (cont’d) • java.security.SecureRandom은 보다 강력한 PRNG, JDK1.1에 소개 되어짐 • SHA-1 메시지 다이제스트 알고리즘을 사용 • SecureRandom은 seed를 사용하여 생성됨 • 보다 많은 의사-난수 생성에 필요 • 메시지 다이제스트의 변경 불가 성질때문에, PRNG의 현재 출력을 알더라도 과거 혹은 미래의 값을 예측하기 힘들다.
SecureRandom (cont’d) • SecureRandom의 사용 • SecureRandom 인스턴스 생성 • nextBytes() 메소드 호출 100bytes의 의사-난수 데이터 생성 SecureRandom sr = new SecureRandom(); byte[] pseudoRandom = new byte[100]; sr.nextBytes(pseudoRandom);
SecureRandom (cont’d) • 두개의 SecureRandom constructors: • public SecureRandom() • SecureRandom을 생성 • 자동적으로 생성된 seed데이터로 초기화 • public SecureRandom(byte[] seed) • 주어진 시드 데이터를 취하고 • 그것을 SecureRandom 인스턴스 초기화에 사용
SecureRandom (cont’d) • 진정한 랜덤 데이터 수집시, setSeed()를 사용하여 SecureRandom의 시드를 갱신 • public synchronized void setSeed(byte[] seed) • SecureRandom의 내부 상태 갱신 • 의사-난수 데이터 필요시, nextBytes()를 호출 • public synchronized void nextBytes(byte[] bytes) • 주어진 바이트배열을 의사-난수 데이터로 채운다
Self-Seeding • SecureRandom을 생성할때 seed 값을 기술하지 않으면, 자동으로 생성된다. • 시스템 상의 thread 타이밍에 기초한 알고리즘을 사용하여 seed 발생기는 seed를 얻는다. • 시간 걸림(몇초) • 완전히 검증되지 않았고, 암호 해독가들이 이용할수 있는 약점이 있다.
Keyboard Timing • SecureRandom에 seed하는 또 다른 메소드. • 키보드 이벤트 타이밍을 측정하는 PGP(Pretty Good Privacy)에서 사용되어져온 메소드에 기초 • 빠른 타이머를 이용하여 keystroke 사이의 간격을 계측하고, 그 시간의 낮은 자리 비트를 하나 혹은 두개를 취한다. • 사용자가 몇 초간의 데이터를 입력해야하므로 불편하다.
Seeder • KeyEvents에 따라 일정한 길이의 seed 값을 만든다. • Seeder는 키보드 이벤트가 어디로부터 오는지 상관하지 않는다. • 단지 KeyListener interface를 구현 package oreilly.jonathan.util; import java.awt.AWTEventMulticaster; import java.awt.event.*; public class Seeder implements KeyListener {
Seeder (cont’d) protected byte[] mSeed; //mSeed에 seed 값 저장 protected int mBitIndex; // 현재 비트 인덱스 protected boolean mDone; // seed 수집 완료 indicate protected char mLastKeyChar; //반복된 키 거부를 위해 //마지막 키 값 저장 protected ActionListener mListenerChain; protected Counter mCounter; // 키보드 이벤트 간의 // 시간을 측정하는 트랙유지
Seeder (cont’d) public Seeder (int seedBytes) {reset(seedBytes);} // 하나의 생성함수,reset() 메소드 호출 public void reset(int seedBytes) { mSeed = new byte[seedBytes]; mBitIndex = seedBytes * 8 -1; mDone = false; mLastKeyChar = '\0'; mListenerChain = null; // reset()는 Seeder를 초기화
Seeder (cont’d) public byte[] getSeed() { return mSeed;} public int getBitLength() { return mSeed.length * 8;} // Seeder에 유용한 정보제공 public int getCurrentBitIndex(){ return mSeed.length * 8 - 1 - mBitIndex; } //mBitIndex는 감소 카운트 public void addActionListener (ActionListener al) { mListenerChain = AWTEventMulticaster.add(mListenerChain, al); } // seed 발생시 통고 바라는 객체의 등록 public void removeActionListener (ActionListener al){ mListenerChain = AWTEventMulticaster.remove(mListenerChain, al); } // seed 발생시 통고 바라는 객체의 등록취소
Seeder (cont’d) Seeder는 KeyListener로서 키의 눌림을 인식하고 이벤트를 발생한다. 반복된 키를 걸러내고 keyTyped()에서 grabTimeBit()를 호출 public void keyPressed(KeyEvent ke) {} public void keyReleased(KeyEvent ke) {} public void keyTyped(KeyEvent ke) { char keyChar = ke.getKeyChar(); if (keyChar != mLastKeyChar) grabTimeBit(); mLastKeyChar = keyChar; }
Seeder (cont’d) protected void grabTimeBit() { if (mDone) return; int t = mCounter.getCount(); //Counter로 부터 count 가져옴 int bit = t & 0x0001; //하나의 비트를 벗겨냄 if (bit != 0) { int seedIndex = mBitIndex / 8; int shiftIndex = mBitIndex % 8; mSeed[seedIndex] |= (bit << shiftIndex); //그 비트가 0이 아니면 seed 값 갱신
Seeder (cont’d) mBitIndex--; if (mBitIndex < 0) { mCounter.stop(); mBitIndex = 0; // Reset this so getCurrentBitIndex() works. mDone = true; // seed 완료 if (mListenerChain != null) { mListenerChain.actionPerformed( new ActionEvent (this, 0, "Your seed is ready.")); } } } }
Seeder (cont’d) • Seeder 사용 3단계 • Seeder 생성 Seeder s = new Seeder(20); • KeyEvents의 소스를 Seeder에 엮는다. theComponent.addKeyListener(s); • ActionEvent 등록 s.addActionListener(this);
AWTEventMulticaster • Seeder는 다중 ActionListener의 트랙을 유지하면서, 제공된 변수는 하나이다. • AWTEventMulticaster는 새로운 listener의 추가를 다루며, 이전의 ActionListeners와 새로운 ActionLister를 담는 새로운 객체를 생성한다. • 단지 한 개의 ActionListener변수인 mListenerChain만 있어도 모든 객체를 참조하므로 하나만으로 족하다.
Pitfalls • Seeder 설계의 쟁점 • 미묘한 타이밍 문제 • Counter가 Seeder에 리턴하는 값에 어떤 규칙이 있는지를 확신할 수 없다. • 반복되는 키들의 위험성 • 반복되는 키들의 타이밍은 매우 규칙적이다. • 반복키를 걸러내어 함정을 피한다. • 그러나, 키보드 장치 자체의 interval로 인해, 그것보다 빠르게 입력되면 규칙적인 타이밍이 만들어 질수 있다.
Pitfalls (cont’d) • random에 대한 통계학적 검증을 거쳐도 랜덤인지 확신할 수 없다. • http://random.mat.sbg.ac.at/ • Salzbug대학, 난수 발생기와 난수 검사정보 • random에 대한 문헌과 다른 사이트 링크 • http://www.cs.berkeley.edu/~daw/netscape-randomness.html • 논문, 소스 코드, 하드웨어 사양, 링크 리스트 • http://lavarand.sgi.com/ • Lava Lites가 난수 발생에 어떻게 사용되는지 설명
SeederDialog • Seed 값을 얻는데 사용되는 모델 다이얼로그 • 사용 SeederDialog sd = new SeederDialog(this, 20); sd.show(); byte[] seed = sd.getSeed();
SeederDialog (cont’d) • Source Code package oreilly.jonathan.awt; import java.awt.*; import java.awt.event.*; import oreilly.jonathan.util.*; public class SeederDialog extends Dialog implements ActionListener, KeyListener { ProgressBar mProgressBar; Seeder mSeeder; public SeederDialog(Frame parent, int seedBytes) { super(parent, "Seeder Dialog", true); setupWindow(seedBytes); }
SeederDialog (cont’d) public byte[] getSeed() { return mSeeder.getSeed(); } // Seeder 객체로부터 seed 값을 리턴 public void actionPerformed(ActionEvent ae) { dispose(); } // Seeder로부터 ActionEvent를 돌려받는다. public void keyPressed(KeyEvent ke) {} public void keyReleased(KeyEvent ke) {} public void keyTyped(KeyEvent ke) { mProgressBar.setLevel(mSeeder.getCurrentBitIndex()); } 나머지 source code 생략