자바 스크립트에서 난수를 확보 하시겠습니까?


80

자바 스크립트에서 암호화 보안 난수를 어떻게 생성합니까?


3
"암호화"란 정확히 무엇을 의미합니까? 0과 1 사이의 난수를 반환하려면 Math.random ()을 사용하십시오. 실제 난수를 생성하는 (간단한) 방법이 없기 때문에 기술적으로 의사 난수입니다.
Logic Artist

26
나는 질문이 암호화에 적합한 난수 생성기를 요구하고 있다고 생각합니다. 예 : 기본적으로 여러 언어로 구현 된 모듈로 RND는 적합하지 않습니다.
winwaed


18
@Logic Artist-아니요, Math.random은 암호 학적으로 안전 하지 않습니다 . 암호화 보안은 가치를 예측하거나 무작위와 구별하기 위해 상당한 시간과 에너지를 투자하려는 적에게도 가치를 예측할 수 없음을 의미하는 표준 용어입니다.
DW

답변:


24

예를 들어 마우스 움직임을 난수에 대한 시드로 사용하고, onmousemove 이벤트가 발생할 때마다 시간과 마우스 위치를 읽고, 해당 데이터를 미백 기능에 공급하면 임의의 일류 클래스를 가질 수 있습니다. 데이터를 사용하기 전에 사용자가 마우스를 충분히 움직 였는지 확인하십시오.

편집 : 나는 암호 생성기를 만들어서 개념을 조금 가지고 놀았습니다. 내 미백 기능이 완벽하다는 것을 보장하지는 않지만 지속적으로 다시 시드되는 것은 작업에 충분하다고 확신합니다 : ebusiness.hopto.org /generator.htm

Edit2 : 이제 스마트 폰에서 작동하지만 엔트로피가 수집되는 동안 터치 기능을 비활성화하는 경우에만 작동합니다. Android는 다른 방식으로 제대로 작동하지 않습니다.


11
다음은 BSD 라이센스가있는 암호화 라이브러리와 난수 생성기입니다. crypto.stanford.edu/sjcl
aaaaaaaaaaaa

이는 OP 요구 사항을 충족하는 것으로 보입니다.
James K. Polk 회장

SJCL (Stanford Crypto Library)은 훌륭한 선택처럼 보입니다. 그들은 암호 학적으로 난수를 생성하는 방법을 자세히 설명하는 출판 된 논문을 가지고 있으며 그들의 접근 방식은 견고하고 신중하게 보입니다.
DW

eBusiness 제안이 있습니다. .password span복사 / 붙여 넣기 / 조작을 쉽게하기 위해 해당 문자열이 각 태그 사이에 삽입되도록하는 구분자 필드를 추가합니다 . 예를 들어 현재 생성 된 문자열을 복사하여 붙여 넣으면 하나의 긴 문자열로 붙여 넣습니다.
trusktr

마우스가 없기 때문에 모바일 플랫폼에서는 작동하지 않으므로이 기능을 사용하는 사용자는 대체 난수 소스가 필요합니다.
Matt Eskridge 2014 년

61

window.crypto 객체에 이것을 추가하는 것에 대해 WHATWG에서 논의했습니다. 당신이 읽을 수있는 논의를 하고 체크 아웃 제안 API 와 웹킷 버그 (22,049)을.

임의의 바이트를 얻기 위해 Chrome 에서 다음 코드 테스트했습니다 .

(function(){
  var buf = new Uint8Array(1);
  window.crypto.getRandomValues(buf);
  alert(buf[0]);
})();


바꿀 경우는 IE 11에서 작동 window.crypto으로 window.msCrypto.
Michael Kropat

28

순서대로, 최선의 방법은 다음과 같습니다.

  1. window.crypto.getRandomValues ​​또는 window.msCrypto.getRandomValues
  2. sjcl 라이브러리의 randomWords 함수 ( http://crypto.stanford.edu/sjcl/ )
  3. isaac 라이브러리의 난수 생성기 (Math.random에 의해 시드되므로 실제로 암호화되지 않음) ( https://github.com/rubycon/isaac.js )

window.crypto.getRandomValues는 한동안 Chrome에서 구현되었으며 비교적 최근에는 Firefox에서도 구현되었습니다. 안타깝게도 Internet Explorer 10 이하에서는이 기능을 구현하지 않습니다. IE 11에는 동일한 작업을 수행하는 window.msCrypto가 있습니다. sjcl에는 마우스 움직임에서 시드 된 큰 난수 생성기가 있지만 마우스가 생성기를 시드 할만큼 충분히 움직이지 않았거나 사용자가 마우스 움직임이 전혀없는 모바일 장치에있을 가능성이 항상 있습니다. 따라서 선택의 여지가없는 경우 보안되지 않은 난수를 얻을 수있는 대체 사례를 사용하는 것이 좋습니다. 이 작업을 처리 한 방법은 다음과 같습니다.

function GetRandomWords (wordCount) {
    var randomWords;

    // First we're going to try to use a built-in CSPRNG
    if (window.crypto && window.crypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.crypto.getRandomValues(randomWords);
    }
    // Because of course IE calls it msCrypto instead of being standard
    else if (window.msCrypto && window.msCrypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.msCrypto.getRandomValues(randomWords);
    }
    // So, no built-in functionality - bummer. If the user has wiggled the mouse enough,
    // sjcl might help us out here
    else if (sjcl.random.isReady()) {
        randomWords = sjcl.random.randomWords(wordCount);
    }
    // Last resort - we'll use isaac.js to get a random number. It's seeded from Math.random(),
    // so this isn't ideal, but it'll still greatly increase the space of guesses a hacker would
    // have to make to crack the password.
    else {
        randomWords = [];
        for (var i = 0; i < wordCount; i++) {
            randomWords.push(isaac.rand());
        }
    }

    return randomWords;
};

해당 구현을 위해 sjcl.js 및 isaac.js를 포함해야하며 페이지가로드되는 즉시 sjcl 엔트로피 수집기를 시작해야합니다.

sjcl.random.startCollectors();

sjcl은 이중 라이선스 BSD 및 GPL이고 isaac.js는 MIT이므로 모든 프로젝트에서 둘 중 하나를 사용하는 것이 완벽하게 안전합니다. 다른 답변에서 언급했듯이 clipperz는 또 다른 옵션이지만 기괴한 이유가 무엇이든 AGPL에 따라 라이센스가 부여됩니다. JavaScript 라이브러리에 어떤 의미가 있는지 이해하는 사람은 아직 보지 못했지만 보편적으로 피하고 싶습니다.

내가 게시 한 코드를 개선하는 한 가지 방법은 isaac 난수 생성기의 상태를 localStorage에 저장하는 것이므로 페이지가로드 될 때마다 다시 시드되지 않습니다. Isaac은 임의의 시퀀스를 생성하지만 암호화를 위해 시드가 매우 중요합니다. Math.random으로 시드하는 것은 나쁘지만 모든 페이지로드에 반드시 필요한 것은 아니라면 적어도 조금 덜 나쁩니다.


저는 github.com/simbo1905/srp-6a-demo/blob/master/srp/Client/lib/… 에서이 접근 방식을 따라 무작위 128 16 진수를 생성했습니다. 사용자 window.crypto 그렇지 않으면 isaac. isaac을 사용해야하는 경우 0.1 초 동안 무작위를 건너 뛰어 페이지로드시 생성기를 워밍업합니다. 텍스트 입력 필드 onkeyup은 또한 random16byteHex.advance(Math.floor(event.keyCode/4));몇 밀리 초 동안 난수를 앞으로 건너 뛰는 역할도합니다. 그러면 해당 브라우저 앱에서 사용되는 isaac 랜덤이 사용자 입력과 하드웨어 / 브라우저 속도에 따라 달라 지므로 추측하기가 매우 어렵습니다.
simbo1905

1
@ZeroG SJCL에 대한 귀하의 의견에 대해 "마우스가 생성기를 시드 할만큼 충분히 움직이지 않았거나 사용자가 마우스 움직임이 전혀없는 모바일 장치에있을 가능성이 항상 있습니다. " . 이제 엔트로피가 touchmove( pull # 151 ) 및 devicemotion( pull # 79 ) 에서 수집되므로 모바일 장치에서 잘 작동합니다 .
TachyonVortex

1
sjcl이 이미 window.crypto를 사용 하고있는 것으로 보입니다.
Ales

14

다음 window.crypto.getRandomValues과 같이 사용하십시오 .

var random_num = new Uint8Array(2048 / 8); // 2048 = number length in bits
window.crypto.getRandomValues(random_num);

이는 모든 최신 브라우저에서 지원되며 운영 체제의 임의 생성기 (예 :) 를 사용합니다 /dev/urandom. IE11 호환성이 필요한 경우에는 접두사가 붙은 구현을 사용해야합니다 var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..).

있습니다 window.cryptoAPI는 또한 수 크게 키를 생성 더 좋은 옵션이 될 수있다.


나는 당신이 Uint8Array를 의미한다고 생각합니다 (맞춤법 검사)
Flyingkiwi

1
여기서 "키 길이"가 올바른 용어입니까? 키 길이는 비트로 표시되지 않습니까?
Indolering

1
특정 범위 (예 : 4000-64000)에서 난수를 생성하려면 window.crypto.getRandomValues를 어떻게 사용하고 매번 난수 1 개가 필요합니다.
Sid

2
@Sid 훌륭한 질문처럼 들립니다. 물어보세요 !
phihag

2
@phihag : 이미했습니다. 지금까지 답변이 없습니다. stackoverflow.com/questions/41437492/…
Sid

6

범위 [0, 1)(와 유사 Math.random()) 에서 강력한 암호화 번호를 얻으려면 crypto 사용하십시오 .

let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;

console.log( random() );


4

http://sourceforge.net/projects/clipperzlib/ 시도해 볼 수 있습니다 . 암호화 보안 난수 생성기 인 Fortuna 를 구현했습니다 . (src / js / Clipperz / Crypto / PRNG.js를보세요). 마우스를 임의의 소스로 사용하는 것으로 보입니다.


라이브러리에 대한 더 자세한 정보는 여기 clipperz.com/open_source/javascript_crypto_library
ameer

1
좋은 대답은 불행히도 내 프로젝트와 호환되지 않는다고 생각하는 AGPL에 따라 라이센스가 부여되었습니다.
Kyle

2014 년 5 월 2 일부터 Clipperz는 커밋 c9f12e87c7ac88e4612de4d1d70df7c53f77e2ad
GGG

1

우선 엔트로피 소스가 필요합니다. 예를 들어, 마우스, 암호 또는 기타 이동. 그러나 이러한 모든 소스는 무작위와는 거리가 멀고 거의 20 비트의 엔트로피를 보장합니다. 다음 단계는 "암호 기반 KDF"와 같은 메커니즘을 사용하는 것입니다. 이렇게하면 데이터를 무작위와 구별하기가 계산적으로 어렵습니다.


0

수년 전에는 자신 만의 난수 생성기를 구현하고 마우스 움직임과 타이밍 정보로 수집 된 엔트로피를 시드해야했습니다. 이것은 JavaScript 암호화의 플로지스톤 시대였습니다. 요즘 우리는 window.crypto함께 일해야 합니다.

당신이 임의의 필요한 경우 정수를 , 난수-CSPRNG는 좋은 선택이 될 것입니다. 일련의 임의 바이트를 안전하게 생성 한 다음이를 편향되지 않은 임의의 정수로 변환합니다.

const randomInt = require("random-number-csprng");
(async function() {
    let random = randomInt(10, 30);
    console.log(`Your random number: ${random}`);
})();

임의의 부동 소수점 숫자가 필요한 경우 조금 더 작업을해야합니다. 그러나 일반적으로 보안 임의성은 부동 소수점 문제가 아니라 정수 문제입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.