我正在将用Python编写的模块转换为Perl 6。在这个模块中,有一个名为create_key的方法,它使用os.urandom进行加密:
def create_key(size):
return binascii.hexlify(os.urandom(size))[:16]文档将os.urandom描述为:
返回适合加密使用的大小随机字节的字符串。
在Perl 6中,有一个名为Buf的类,但它没有随机方法。那么如何使用Perl 6实现os.urandom(size)呢?
发布于 2019-01-02 20:59:57
您可以一直使用Python的urandom
sub py-urandom( UInt $size ){
use Inline::Python;
state $py = Inline::Python.new; # reuse the same instance
once $py.import('os'); # load the Python os library only once
$py.call('os','urandom', $size);
}
say py-urandom(10)».fmt('%02X').join; # 1473A7D5455F15D3726B要使上面的工作正常进行,需要安装python-dev操作系统包。然后用Inline::Python安装zef。
你也可以使用binascii.hexlify
sub create-key ( UInt $size ) {
use Inline::Python;
state $py = Inline::Python.new;
once $py.import('os');
once $py.import('binascii');
$py.call('binascii','hexlify', $py.call('os','urandom',$size)).decode('ascii');
}我确信有更好的方法来完成上述工作,但这是我第一次使用Inline::Python。(这是显而易见的,因为我必须安装python-dev才能回答这个问题)
从长远来看,另一种更好的方法是调用getrandom、getentropy或CryptGenRandom,这取决于它是否运行在Linux、OpenBSD或CryptGenRandom上。基本上复制os.urandom的实现。
下面是一个快速编写的例子。
sub urandom ( UInt $size ){
use NativeCall;
my constant is-win = $*DISTRO.is-win;
my constant is-openbsd = $*DISTRO.name eq 'openbsd';
if is-win {
fail "urandom doesn't handle Windows yet";
# It is more involved on Windows, and I don't use Windows
} elsif is-openbsd {
# note that this is untested as I don't use OpenBSD
if $size > 256 {
fail "urandom doesn't handle more than 256 on OpenBSD"
# note that this could be changed to load it in 256 byte chunks
}
sub getentropy( Buf \buf, size_t \buflen --> int32 ) is native {}
my Buf $buf .= allocate($size);
my $result = getentropy( $buf, $size );
fail if $result !== 0;
$buf
} else { # presumably Linux or other UNIX-like
sub getrandom (Buf \buf, size_t \buflen, uint32 \flags --> ssize_t) is native {}
my Buf $buf .= allocate($size);
my $total = getrandom( $buf, $size, 0 );
fail unless $total == $size; # could be changed to call it for the rest
$buf;
}
}say urandom(10)».fmt('%02X').join; # 0EF9EDB3EBC724C0E9CE如果您在使用/dev/urandom的系统中,则可以直接从该系统中读取。
sub urandom ( UInt $size ){
my $urandom will leave {.close}
= '/dev/urandom'.IO.open(:bin,:ro);
$urandom.read( $size )
}
say urandom(10)».fmt('%02X').join; # 01B6C41AD0A77732C328最好的方法是使用像地窖::随机这样已经完成上述功能的模块。
它实现了我没有实现的Windows所需的代码,但是它在*NIX系统上使用/dev/urandom文件。
# alias &Crypt::Random::crypt_random_buf as &urandom
my &urandom = do {
use Crypt::Random;
&crypt_random_buf
}
say urandom(10)».fmt('%02X').join; # 841720513678B1811E2D发布于 2019-01-02 18:37:36
使用该方法或子roll不会给出适合密码学使用的随机字节。他们只是使用perl6提供的内置伪随机数生成器,在moarvm上的rakudo的例子中,这是一个mersenne。
相反,您需要的是像Crypt::Random这样的库,它模仿arc4random,并被描述为在arc4random上使用/dev/urandom,在windows上使用CryptGenRandom。你可以在github上找到它或直接用zef install Crypt::Random安装它。
使用来自该模块的crypt_random_buf子模块将给您一个您想要的buf大小,然后您可以将它转换成一个十六进制数字字符串,就像在另一个答案中一样,使用.list.fmt("%x","")。
发布于 2019-01-02 17:39:41
sub urandom(Int:D \size) { Buf.new: (^256).roll(size) }
say urandom(16); # Buf:0x<98 43 10 A7 5A FD 62 4B AB 1E 42 6D 24 70 E6 89>交替地,作为字符串:
say urandom(16).list.fmt("%x",""); # bfa1c6fef9784ba31b17cdb135ce6622或者把它放到urandom子程序中:
sub urandom(Int:D \size) { Buf.new((^256).roll(size)).list.fmt("%x","") }
say urandom(16); # bfa1c6fef9784ba31b17cdb135ce6622https://stackoverflow.com/questions/54006977
复制相似问题