首页 > 解决方案 > 我应该如何直接使用 UTF8 或 UTF16 随机生成一个固定长度的字符串变量?

问题描述

所以这是我的代码,它基本上会生成一个用于加密的盐。为了生成随机字符,我只是使用了一个预先声明的字符串变量来保存所有字符,因此代码会根据预先声明的变量生成字符串输出

但是,我认为如果我使用一组更大的密钥(例如 UTF8 或 16)来生成盐,结果可能不会那么随机。

static final String keychain = "0123456789qwertyuioasdfghjklzxcvbnm,.+_=-][}{;:></?'|!@#$%^&*()坢坣坥坧坨坩坪坫坬坭坮&quot; ;
static SecureRandom randomValue = new SecureRandom();


public static String GetRandomSalt(){


    StringBuilder constructsalt = new StringBuilder(16);
    for (int i = 0; i < 16; i ++){
        constructsalt.append(keychain.charAt(randomValue.nextInt(keychain.length())));
    }

    System.out.println(constructsalt.toString());
    return constructsalt.toString();


}

那么是否可以参考上面的代码使用 UTF8/16 密钥集直接生成一个随机固定长度的字符串?

标签: javastringhashutf-8salt

解决方案


但是,我认为如果我使用一组更大的密钥(例如 UTF8 或 16)来生成盐,结果可能不会那么随机。

你似乎很困惑。

加密完全在字节上完成。不是字符。字节是数字,从 0 到 255。仅此而已。

但是,如果需要,您可以将字符转换为字节。没有一种固定的方法可以做到这一点。US-ASCII 是一种方式(仅定义 96 个字符,映射到范围 32-127)。UTF-8 是另一种。大多数编码具有不能产生每个可以想象的可能字节序列的特性。只是其中的一个子集。这对加密来说是个坏消息,因此请避免使用字符串。时期。(对于几乎所有的编码,有些字节序列永远不会是将字符串转换为字节的结果)。

getRandomSalt返回字符串的事实?

你搞砸了。那是错误的。它应该返回byte[]

许多加密工具、API 和教程似乎确实使用了字符串这有两个独立的、同样愚蠢的起源:

对字符集的误解

一大堆编程语言随便模糊了字符串和一袋字节之间的区别,并且无法区分 和 之间的"Hello"区别[0,72, 101, 108, 108, 111]。这是一个非常愚蠢的想法——除了英语倾向于使用的字符之外,还有更多的字符,并且整个 unicode 符号集不适合 0-255 范围;毕竟,有超过 256 个独特的字符

幸运的是,Java 并不是一种愚蠢的语言。byte[] 和 String 不可互换,因此,使该方法返回一个byte[].

更容易转移到人的眼球

读 Hello 比读 0、72、101、108、108、111 容易得多。但是,最好的情况、令人困惑的情况和最坏的情况,将事物保留为字符串会严重降低您的键和盐的能力表达随机性。这很糟糕

因此,这替换了您粘贴在问题中的所有代码,并且非常优越:

public byte[] getRandomSalt() {
    byte[] salt = new byte[16];
    random.nextBytes(salt);
    return salt;
}

推荐阅读