乱数

提供: セキュリティ
2018年3月14日 (水) 23:13時点におけるDaemon (トーク | 投稿記録)による版

(差分) ←前の版 | 最新版 (差分) | 次の版→ (差分)
移動: 案内検索
スポンサーリンク

乱数 (random number)とは、ランダムな数列である乱数列の各要素のことです。C言語などでは、rand()関数を呼び出すことで乱数を得られます。OpenSSLコマンドで乱数データを生成したり、Unixでは、デバイスファイル random/urandom を読み出すことでも乱数データを得られます。

読み方

乱数
らんすう
random number
らんだむ なんばー

概要

乱数とは、出現する値に規則性のない数です。 コンピューターでは、必要な範囲内で乱数とみなす擬似乱数を用います。

乱数は、秘密鍵(プライベート鍵)の作成に利用されます。

真の乱数

「真の乱数」は、「サイコロを振った値」です。

「真の乱数」は、以下の条件が必要です。

  • 偏りがない
  • 規則性がない
  • 再現性がない

一般的なサイコロは、1の目は大きな穴があいているなど、偏りが発生します。つまり「弱い乱数」です。カジノで使われる精密ダイス(プレシジョンダイス, Precision Dice)は、出目が限りなく均一で、重心が限りなく中央にあり、重さも均一になっています。

プログラミングにおける乱数

  • C言語では、標準関数 rand() 関数を用いて乱数を生成できます。
  • C++言語では、標準関数 rand() 関数を用いて乱数を生成できます。
  • PHPは、メルセンヌツイスター法のmt_srand(), mt_rand()を使用します。srand(),rand()は、すでにレガシーです。
  • PHPで暗号のための安全な乱数が必要であれば、openssl_random_pseudo_bytes()を使用します。
  • UNIXでは、/dev/random, /dev/urandom のデバイスを読むこと乱数を得られます。
  • OpenSSLコマンドを使用して乱数を生成できます。
  • Rでは、randomパッケージを使用します。大気のノイズを観測して乱数を生成します。

C言語

rand()

/*
 * rand.c
 * Copyright (C) 2014 kaoru <kaoru@bsd>
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
int
main(int argc, char *argv[]) {
        srand( time(NULL) );
        int r = rand ();
        printf ("%d\n", r);
        return 0;
}

/dev/urandom

/dev/urandomを/dev/randomに変更すれば、/dev/randomから読み出します。

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <err.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
 
#include <fcntl.h>
 
#define DEV_RANDOM "/dev/urandom"
#define BUF 256
 
int
get_random (char * const buf, const int buflen, const int len)
{
        if (len > buflen)
        {
                warnx ("buffer size is small (%d / %d)", buflen, len);
                return (-1);
        }
        int fd = open(DEV_RANDOM, O_RDONLY);
        if (fd == -1)
        {
                warn ("can not open %s", DEV_RANDOM);
                return (-1);
        }
        int r = read (fd, buf, len);
        if (r < 0) {
                warn ("can not read");
                return (-1);
        }
        if (r != len)
        {
                warnx ("can not read(%d != %d)", r, len);
                return (-1);
        }
 
        (void) close (fd);
        return (0);
}

PHP

mt_rand

rand()ではなく、mt_rand()を使用します。mt_rand()は、乱数生成器 Mersenne Twister を使用します。平均してlibcのrand()よりも4倍以上高速に乱数を生成できます。 srand()は、seedが必要でしたが、PHP4.2.0以降は、ランダム数生成器にシードが与える必要がなくなりました。

<?php
mt_srand();
echo mt_rand() , PHP_EOL;
?>

5から15まで(両端を含む)の乱数を得るには、範囲を指定します。

<?php
echo mt_rand(5, 15), PHP_EOL;
?>

PHP+OpenSSLモジュール

暗号のために安全な乱数データが欲しい場合には、openssl_random_pseudo_bytes()を使用します。PHPのopensslモジュールが必要になります。

10バイトの乱数が得たい場合、以下のコードになります。

<?php
$data = openssl_random_pseudo_bytes(10);
?>

openssl_random_pseudo_bytes()は、バイト列を返すので、画面にエコーしたいなら16進数にします。

<?php
/**
 * Short description for openssl_random_pseudo_bytes.php
 *
 * @package openssl_random_pseudo_bytes
 * @author kaoru <kaoru@bsd>
 * @copyright (C) 2014 kaoru <kaoru@bsd>
 */
$data = openssl_random_pseudo_bytes(20);
echo bin2hex($data),PHP_EOL;
?>

上記のコードを実行すると、このようになります。

$ php openssl_random_pseudo_bytes.php
b5b9801a5f00cd0f322e59268169982867a944ed

openssl_random_pseudo_bytes は PHP のソースコードの ext/openssl/openssl.c で実装されています。 openssl_random_pseudo_bytes () の実態は、 RAND_pseudo_bytes () です。 RAND_pseudo_bytes() は、 OpenSSL の crypto/rand/rand_lib.c で実装されています。 RAND_pseudo_bytes は、 RAND_get_rand_method() でランダム関数を取得して、呼び出します。内部では、 ENGINE_get_default_RAND()とENGINE_get_RAND() でデフォルトの関数を取得します。デフォルトがなければ、 RAND_SSLeay()が使用されます。 ENGINE_get_default_RANDは engine_table_selectで rand_tableからポインタを返します。

rand

レガシーな rand()のコードは、以下の通りです。

<?php
srand();
echo rand() , PHP_EOL;
echo rand(5, 15), PHP_EOL;
?>

OpenSSL コマンドによる乱数データの生成

OpenSSLコマンドを用いて、100バイトのデータを生成する例です。

openssl rand 100 -out /tmp/rand.100

dd コマンドとrandomデバイスによる乱数データの生成

1MBのファイルを作成する例です。

$ dd if=/dev/random of=urandom.dat count=1024 bs=1024

urandomの場合は、/dev/urandomを指定します。

$ dd if=/dev/urandom of=urandom.dat count=1024 bs=1024

擬似乱数生成アルゴリズム

  • メルセンヌツイスター(mersenne twister)
  • カオス乱数

関連項目




スポンサーリンク