raku - 如何在 Perl 6 中实现 Python 的 os.urandom 方法?

标签 raku

我正在将一个用 Python 编写的模块转换为 Perl 6。在模块中,有一个名为 create_key 的方法,它使用 os.urandom用于加密:

def create_key(size):
    return binascii.hexlify(os.urandom(size))[:16]

该文档描述了 os.urandom作为:

Return a string of size random bytes suitable for cryptographic use.



在 Perl 6 中,有一个名为 Buf 的类。 ,但没有随机的方法。那么如何实现os.urandom(size)使用 Perl 6?

最佳答案

你总是可以只使用 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::Pythonzef .

您可以使用 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 还是 Windows 上运行。基本复制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

最好的方法是使用已经完成上述操作的模块,如 Crypt::Random .
它实现了我没有实现的 Windows 所需的代码,但它使用了 /dev/urandom *NIX 系统上的文件。

# alias &Crypt::Random::crypt_random_buf as &urandom
my &urandom = do {
  use Crypt::Random;
  &crypt_random_buf
}

say urandom(10)».fmt('%02X').join; # 841720513678B1811E2D

关于raku - 如何在 Perl 6 中实现 Python 的 os.urandom 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54006977/

相关文章:

external - 找出外部命令的可运行性

regex - 如何在perl6中找到与regexp匹配的数量?

expression - `do` 关键字是运行 block 还是将其视为表达式?

raku - 如何基于逗号拆分字符串,但不基于双引号中的逗号

object - 在 Raku 中克隆对象

unit-testing - 如何在对模块进行单元测试时模拟导入的子例程

config - 如何更好地处理配置文件?

json - 如何解析 JSON 并添加一些自定义字符串?

raku - 用于抑制接收器上下文的自定义运算符

regex - perl6 空匹配对象为 True?将 Set.one/all 变量插入正则表达式