7
votes

Comment implémenter la méthode os.urandom de Python dans Perl 6?

Je suis en train de convertir un module écrit en Python en Perl 6. Dans le module, il y a une méthode appelée create_key , qui utilise os.urandom pour une utilisation cryptographique:

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

Le document décrit os.urandom comme:

Renvoie une chaîne d'octets aléatoires de taille adaptée à une utilisation cryptographique.

En Perl 6, il existe une classe appelée Buf , mais il y a aucune méthode aléatoire pour cela. Alors, comment implémenter os.urandom (size) en utilisant Perl 6?


4 commentaires

Donc je suis probablement vraiment stupide, mais est-ce que (0..255) .roll ($ size) ferait l'affaire? Vous pouvez ensuite remplir un Buf à partir de cela si vous le souhaitez?


@Scimon Merci. Comme vous l'avez suggéré, j'utilise (Buf.new: (0..255) .roll ($ size)). Unpack ("H *"). Substr (0, 16) , peut-être que cela peut travail.


@chenyf s'il vous plaît gardez à l'esprit que unpack est encore expérimental. Si vous voulez simplement un ensemble de 16 chiffres hexadécimaux aléatoires, disons flat ('A' .. 'F', 0..9) .roll (16) est probablement suffisant.


@jjmerelo merci. Je vais en choisir un qui convient.


3 Réponses :


6
votes
sub urandom(Int:D \size) { Buf.new((^256).roll(size)).list.fmt("%x","") }
say urandom(16);  # bfa1c6fef9784ba31b17cdb135ce6622

1 commentaires

merci, comme Scimon l'a suggéré, fonctionne comme prévu.



10
votes

L'utilisation de la méthode ou du sous roll ne vous donnera pas d'octets aléatoires adaptés à une utilisation cryptographique. Ils utilisent simplement le générateur de nombres pseudo-aléatoires intégré offert par perl6, qui est un twister mersenne dans le cas de rakudo sur moarvm.

Ce que vous voudrez à la place est une bibliothèque comme par exemple Crypt :: Random , qui imite arc4random et est décrite pour utiliser / dev / urandom sur les unités et CryptGenRandom sur windows. Vous pouvez le trouver sur github ou l'installer directement avec zef install Crypt :: Random < / code>.

L'utilisation du sous-marin crypt_random_buf de ce module vous donnera un buf de la taille souhaitée, que vous pourrez ensuite transformer en une chaîne de chiffres hexadécimaux comme dans l'autre réponse, avec .list.fmt ("% x", "") .


0 commentaires

11
votes

Vous pouvez toujours simplement utiliser 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

Pour faire fonctionner ce qui précède, il faut installer le package du système d'exploitation python-dev . Ensuite, installez Inline :: Python avec zef.


Vous pouvez également utiliser binascii.hexlify p>

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

Je suis sûr qu'il existe une meilleure façon de faire ce qui précède, mais c'est la première fois que j'utilise Inline :: Python . (Ce qui devrait être évident car j'ai dû installer python-dev pour répondre à cette question)


Une autre façon, qui peut être meilleure à long terme, est de simplement appelez getrandom , getentropy ou CryptGenRandom selon qu'il fonctionne sous Linux, OpenBSD ou Windows. Copiez en gros l'implémentation de os.urandom .

Voici un exemple rapidement écrit.

say urandom(10)».fmt('%02X').join; # 0EF9EDB3EBC724C0E9CE
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;
  }
}

Si vous êtes sur un système avec / dev / urandom , vous pouvez simplement le lire à la place.

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');
}

Le meilleur moyen serait d'utiliser un module qui fait déjà ce qui précède comme Crypt :: Random .
Il implémente le code requis pour Windows que je n'ai pas fait, mais il utilise le fichier / dev / urandom sur les systèmes * NIX.

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


1 commentaires

Merci, la solution NativeCall et le module Crypt :: Random me conviennent.