使用音频信号创建随机密钥

时间:2017-08-27 17:24:10

标签: java security audio random passwords

我们知道"随机"我们在代码中生成的数字实际上是伪随机的。对于Java,它们默认使用时间戳作为随机种子,之后生成的每个随机数都是从该点向前确定的。

如果您使用随机数生成密码而恶意方知道您生成该密码的日期,则他们只需要在当天的每毫秒内迭代一次。那将是1000 * 60 * 60 * 24 = 8640万。对于复杂的派对来说,这不是一个很大的猜测。着名的爱德华·斯诺登警告说,"假设你的对手每秒能够进行一万亿次猜测。"

问题是,我们如何生成真正的随机数?我想要的是从我的笔记本电脑的麦克风中采样16位音频,并使用两个样本中最不重要的8位来形成种子。这里的想法是音频信号中最不重要的部分是携带噪声的地方。例如,以下是相对完全记录的16位样本中的几个双字节值:

0,19
0,38
0,-49
1,93
1,-29
1,-80

您可以看到最重要的字节是0或1,这意味着正在记录的波几乎没有注册。另一方面,最低有效字节值在整个地方跳跃。那是随机种子的肥沃土壤!

这篇文章的具体问题是:我们如何使用我们周围真实世界噪音产生的噪音信号生成一个随机的32个字符的密码。

1 个答案:

答案 0 :(得分:-1)

这是一个不错的下午项目!这是一个带有静态方法的实用程序类,它可以生成一个随机整数数组或一个所需长度的随机字符串。

Gist link.

import javax.sound.sampled.*;

public class RandomFromAudio {

    public static final String ALLOWED_CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    // Demonstrating the methods
    public static void main(String[] args) {
        System.out.println(getRandomKey(32));
    }

    public static String getRandomKey(int keyLength) {
        int [] randomInts = getRandomIntArray(keyLength);
        StringBuilder stringBuilder = new StringBuilder();
        for (int randomInt: randomInts) {
            char randomChar = ALLOWED_CHARACTERS.charAt(randomInt % ALLOWED_CHARACTERS.length());
            stringBuilder.append(randomChar);
        }
        return stringBuilder.toString();
    }

    public static int [] getRandomIntArray(int desiredLength) {
        int [] out = null;
        AudioFormat format = new AudioFormat(8000.0f, 16, 1, true, true);
        TargetDataLine microphone;
        try {
            out = new int[desiredLength];
            byte[] data = new byte[2];

            DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
            microphone = (TargetDataLine) AudioSystem.getLine(info);
            microphone.open(format);
            microphone.start();

            // my microphone seems to need to "warm up".
            // It gets a lot of low signal at the beginning producing a lot of low numbers.
            // This loop reads signal until it shows that a decently high value can be reached.
            while (data[1] < 100) {
                microphone.read(data, 0, data.length);
            }
            byte [] leastSig = new byte[2];
            for (int i = 0; i < desiredLength * 2; i++) {
                microphone.read(data, 0, data.length);
                // saving the least significant byte
                leastSig[i % 2] = data[1];
                if (i % 2 == 1) {
                    // combining the bytes into an int
                    out[(i + 1) / 2 - 1] = leastSig[0]<<8 &0xFF00 | leastSig[1]&0xFF;
                }
            }
            microphone.close();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
        return out;
    }
}

运行几次(对我来说)产生了:

hqctXiTiV67iI2JAXrcU0vzGhxEBDN2R
ViCSGxahmI51mXfBIV7INo9vu3ZuKNDi
9oTl1Meer59Y69yxNRTa0Dv3pWNywZFY
zfLrh9ZU8oNLg43M1D1ZzcoSxJ4X1HOQ
dlhliKxM4tAhr8uoCOtdRsmwARIE6Gjb