| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Sodium::FFI; | 
| 2 | 9 |  |  | 9 |  | 947128 | use strict; | 
|  | 9 |  |  |  |  | 114 |  | 
|  | 9 |  |  |  |  | 259 |  | 
| 3 | 9 |  |  | 9 |  | 68 | use warnings; | 
|  | 9 |  |  |  |  | 18 |  | 
|  | 9 |  |  |  |  | 358 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | our $VERSION = '0.009'; | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 9 |  |  | 9 |  | 53 | use Carp qw(croak); | 
|  | 9 |  |  |  |  | 16 |  | 
|  | 9 |  |  |  |  | 437 |  | 
| 8 | 9 |  |  | 9 |  | 77 | use Exporter qw(import); | 
|  | 9 |  |  |  |  | 26 |  | 
|  | 9 |  |  |  |  | 377 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 | 9 |  |  | 9 |  | 4071 | use Alien::Sodium; | 
|  | 9 |  |  |  |  | 447310 |  | 
|  | 9 |  |  |  |  | 81 |  | 
| 11 | 9 |  |  | 9 |  | 224145 | use FFI::Platypus; | 
|  | 9 |  |  |  |  | 64578 |  | 
|  | 9 |  |  |  |  | 332 |  | 
| 12 | 9 |  |  | 9 |  | 74 | use Path::Tiny qw(path); | 
|  | 9 |  |  |  |  | 22 |  | 
|  | 9 |  |  |  |  | 627 |  | 
| 13 | 9 |  |  | 9 |  | 4256 | use Sub::Util qw(set_subname); | 
|  | 9 |  |  |  |  | 3039 |  | 
|  | 9 |  |  |  |  | 1331 |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | # these are the methods we can easily attach | 
| 16 |  |  |  |  |  |  | our @EXPORT_OK = qw( | 
| 17 |  |  |  |  |  |  | randombytes_random randombytes_uniform | 
| 18 |  |  |  |  |  |  | sodium_version_string sodium_library_version_minor sodium_base64_encoded_len | 
| 19 |  |  |  |  |  |  | crypto_aead_aes256gcm_keygen crypto_aead_chacha20poly1305_keygen | 
| 20 |  |  |  |  |  |  | crypto_aead_chacha20poly1305_ietf_keygen crypto_auth_keygen | 
| 21 |  |  |  |  |  |  | ); | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | # add the various C Constants | 
| 24 |  |  |  |  |  |  | push @EXPORT_OK, qw( | 
| 25 |  |  |  |  |  |  | crypto_auth_BYTES crypto_auth_KEYBYTES | 
| 26 |  |  |  |  |  |  | SODIUM_VERSION_STRING SIZE_MAX randombytes_SEEDBYTES SODIUM_LIBRARY_MINIMAL | 
| 27 |  |  |  |  |  |  | SODIUM_LIBRARY_VERSION_MAJOR SODIUM_LIBRARY_VERSION_MINOR | 
| 28 |  |  |  |  |  |  | sodium_base64_VARIANT_ORIGINAL sodium_base64_VARIANT_ORIGINAL_NO_PADDING | 
| 29 |  |  |  |  |  |  | sodium_base64_VARIANT_URLSAFE sodium_base64_VARIANT_URLSAFE_NO_PADDING | 
| 30 |  |  |  |  |  |  | crypto_aead_aes256gcm_KEYBYTES crypto_aead_aes256gcm_NPUBBYTES crypto_aead_aes256gcm_ABYTES | 
| 31 |  |  |  |  |  |  | HAVE_AEAD_DETACHED HAVE_AESGCM | 
| 32 |  |  |  |  |  |  | crypto_aead_chacha20poly1305_KEYBYTES crypto_aead_chacha20poly1305_NPUBBYTES | 
| 33 |  |  |  |  |  |  | crypto_aead_chacha20poly1305_ABYTES | 
| 34 |  |  |  |  |  |  | crypto_aead_chacha20poly1305_IETF_KEYBYTES crypto_aead_chacha20poly1305_IETF_NPUBBYTES | 
| 35 |  |  |  |  |  |  | crypto_aead_chacha20poly1305_IETF_ABYTES | 
| 36 |  |  |  |  |  |  | crypto_sign_SEEDBYTES crypto_sign_BYTES crypto_sign_SECRETKEYBYTES crypto_sign_PUBLICKEYBYTES | 
| 37 |  |  |  |  |  |  | crypto_box_SEALBYTES crypto_box_PUBLICKEYBYTES crypto_box_SECRETKEYBYTES | 
| 38 |  |  |  |  |  |  | crypto_box_MACBYTES crypto_box_NONCEBYTES crypto_box_SEEDBYTES crypto_box_BEFORENMBYTES | 
| 39 |  |  |  |  |  |  | ); | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | our $ffi; | 
| 42 |  |  |  |  |  |  | BEGIN { | 
| 43 | 9 |  |  | 9 |  | 104 | $ffi = FFI::Platypus->new(api => 1, lib => Alien::Sodium->dynamic_libs); | 
| 44 | 9 |  |  |  |  | 147229 | $ffi->bundle(); | 
| 45 |  |  |  |  |  |  | } | 
| 46 |  |  |  |  |  |  | # All of these functions don't need to be gated by version. | 
| 47 |  |  |  |  |  |  | $ffi->attach('randombytes_random' => [] => 'uint32'); | 
| 48 |  |  |  |  |  |  | $ffi->attach('randombytes_uniform' => ['uint32'] => 'uint32'); | 
| 49 |  |  |  |  |  |  | $ffi->attach('sodium_version_string' => [] => 'string'); | 
| 50 |  |  |  |  |  |  | $ffi->attach('sodium_library_version_major' => [] => 'int'); | 
| 51 |  |  |  |  |  |  | $ffi->attach('sodium_library_version_minor' => [] => 'int'); | 
| 52 |  |  |  |  |  |  | $ffi->attach('sodium_base64_encoded_len' => ['size_t', 'int'] => 'size_t'); | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | sub crypto_aead_aes256gcm_keygen { | 
| 55 | 0 |  |  | 0 | 1 | 0 | my $len = Sodium::FFI::crypto_aead_aes256gcm_KEYBYTES; | 
| 56 | 0 |  |  |  |  | 0 | return Sodium::FFI::randombytes_buf($len); | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub crypto_aead_chacha20poly1305_ietf_keygen { | 
| 60 | 2 |  |  | 2 | 1 | 2365 | my $len = Sodium::FFI::crypto_aead_chacha20poly1305_IETF_KEYBYTES; | 
| 61 | 2 |  |  |  |  | 9 | return Sodium::FFI::randombytes_buf($len); | 
| 62 |  |  |  |  |  |  | } | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | sub crypto_aead_chacha20poly1305_keygen { | 
| 65 | 2 |  |  | 2 | 1 | 2273 | my $len = Sodium::FFI::crypto_aead_chacha20poly1305_KEYBYTES; | 
| 66 | 2 |  |  |  |  | 8 | return Sodium::FFI::randombytes_buf($len); | 
| 67 |  |  |  |  |  |  | } | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | sub crypto_auth_keygen { | 
| 70 | 1 |  |  | 1 | 1 | 926 | my $len = Sodium::FFI::crypto_auth_KEYBYTES; | 
| 71 | 1 |  |  |  |  | 4 | return Sodium::FFI::randombytes_buf($len); | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | our %function = ( | 
| 75 |  |  |  |  |  |  | # int | 
| 76 |  |  |  |  |  |  | # crypto_auth(unsigned char *out, const unsigned char *in, | 
| 77 |  |  |  |  |  |  | #     unsigned long long inlen, const unsigned char *k); | 
| 78 |  |  |  |  |  |  | 'crypto_auth' => [ | 
| 79 |  |  |  |  |  |  | ['string', 'string', 'size_t', 'string'] => 'int', | 
| 80 |  |  |  |  |  |  | sub { | 
| 81 |  |  |  |  |  |  | my ($xsub, $msg, $key) = @_; | 
| 82 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 83 |  |  |  |  |  |  | my $key_len = length($key); | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | unless($key_len == Sodium::FFI::crypto_auth_KEYBYTES) { | 
| 86 |  |  |  |  |  |  | croak("Secret key length should be crypto_auth_KEYBYTES bytes"); | 
| 87 |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | my $mac = "\0" x Sodium::FFI::crypto_auth_BYTES; | 
| 90 |  |  |  |  |  |  | my $real_len = 0; | 
| 91 |  |  |  |  |  |  | my $ret = $xsub->($mac, $msg, $msg_len, $key); | 
| 92 |  |  |  |  |  |  | croak("Internal error") unless $ret == 0; | 
| 93 |  |  |  |  |  |  | return $mac; | 
| 94 |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  | ], | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | # int | 
| 98 |  |  |  |  |  |  | # crypto_auth_verify(const unsigned char *h, const unsigned char *in, | 
| 99 |  |  |  |  |  |  | #     unsigned long long inlen, const unsigned char *k); | 
| 100 |  |  |  |  |  |  | 'crypto_auth_verify' => [ | 
| 101 |  |  |  |  |  |  | ['string', 'string', 'size_t', 'string'] => 'int', | 
| 102 |  |  |  |  |  |  | sub { | 
| 103 |  |  |  |  |  |  | my ($xsub, $mac, $msg, $key) = @_; | 
| 104 |  |  |  |  |  |  | my $mac_len = length($mac); | 
| 105 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 106 |  |  |  |  |  |  | my $key_len = length($key); | 
| 107 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | unless ($key_len == Sodium::FFI::crypto_auth_KEYBYTES) { | 
| 110 |  |  |  |  |  |  | croak("Secret key length should be crypto_auth_KEYBYTES bytes"); | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  | unless ($mac_len == Sodium::FFI::crypto_auth_BYTES) { | 
| 113 |  |  |  |  |  |  | croak("authentication tag length should be crypto_auth_BYTES bytes"); | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | my $ret = $xsub->($mac, $msg, $msg_len, $key); | 
| 117 |  |  |  |  |  |  | return 1 if $ret == 0; | 
| 118 |  |  |  |  |  |  | return 0; | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  | ], | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | # int | 
| 123 |  |  |  |  |  |  | # crypto_aead_chacha20poly1305_ietf_decrypt(unsigned char *m, | 
| 124 |  |  |  |  |  |  | #     unsigned long long *mlen_p, | 
| 125 |  |  |  |  |  |  | #     unsigned char *nsec, | 
| 126 |  |  |  |  |  |  | #     const unsigned char *c, | 
| 127 |  |  |  |  |  |  | #     unsigned long long clen, | 
| 128 |  |  |  |  |  |  | #     const unsigned char *ad, | 
| 129 |  |  |  |  |  |  | #     unsigned long long adlen, | 
| 130 |  |  |  |  |  |  | #     const unsigned char *npub, | 
| 131 |  |  |  |  |  |  | #     const unsigned char *k); | 
| 132 |  |  |  |  |  |  | 'crypto_aead_chacha20poly1305_ietf_decrypt' => [ | 
| 133 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'string', 'size_t', 'string', 'size_t', 'string', 'string'] => 'int', | 
| 134 |  |  |  |  |  |  | sub { | 
| 135 |  |  |  |  |  |  | my ($xsub, $ciphertext, $ad, $nonce, $key) = @_; | 
| 136 |  |  |  |  |  |  | my $ciphertext_len = length($ciphertext); | 
| 137 |  |  |  |  |  |  | my $ad_len = length($ad); | 
| 138 |  |  |  |  |  |  | my $nonce_len = length($nonce); | 
| 139 |  |  |  |  |  |  | my $key_len = length($key); | 
| 140 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | unless ($nonce_len == Sodium::FFI::crypto_aead_chacha20poly1305_IETF_NPUBBYTES) { | 
| 143 |  |  |  |  |  |  | croak("Nonce length should be crypto_aead_chacha20poly1305_IETF_NPUBBYTES bytes"); | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  | unless($key_len == Sodium::FFI::crypto_aead_chacha20poly1305_IETF_KEYBYTES) { | 
| 146 |  |  |  |  |  |  | croak("Secret key length should be crypto_aead_chacha20poly1305_IETF_KEYBYTES bytes"); | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  | if ($ciphertext_len < Sodium::FFI::crypto_aead_chacha20poly1305_IETF_ABYTES) { | 
| 149 |  |  |  |  |  |  | croak("cipher text length not right"); | 
| 150 |  |  |  |  |  |  | } | 
| 151 |  |  |  |  |  |  | my $msg_len = $ciphertext_len; | 
| 152 |  |  |  |  |  |  | if ($msg_len > $SIZE_MAX) { | 
| 153 |  |  |  |  |  |  | croak("Message length greater than max size"); | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  | my $msg = "\0" x $msg_len; | 
| 156 |  |  |  |  |  |  | my $real_len = 0; | 
| 157 |  |  |  |  |  |  | my $ret = $xsub->($msg, \$real_len, undef, $ciphertext, $ciphertext_len, $ad, $ad_len, $nonce, $key); | 
| 158 |  |  |  |  |  |  | croak("Internal error") unless $ret == 0; | 
| 159 |  |  |  |  |  |  | if ($real_len <= 0 || $real_len >= $SIZE_MAX || $real_len > $msg_len) { | 
| 160 |  |  |  |  |  |  | croak("Invalid resultant length"); | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  | if ($real_len >= $SIZE_MAX || $real_len > $msg_len) { | 
| 163 |  |  |  |  |  |  | croak("arithmetic overflow"); | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  | return substr($msg, 0, $real_len); | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  | ], | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | # int | 
| 170 |  |  |  |  |  |  | # crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char *c, | 
| 171 |  |  |  |  |  |  | #     unsigned long long *clen_p, | 
| 172 |  |  |  |  |  |  | #     const unsigned char *m, | 
| 173 |  |  |  |  |  |  | #     unsigned long long mlen, | 
| 174 |  |  |  |  |  |  | #     const unsigned char *ad, | 
| 175 |  |  |  |  |  |  | #     unsigned long long adlen, | 
| 176 |  |  |  |  |  |  | #     const unsigned char *nsec, | 
| 177 |  |  |  |  |  |  | #     const unsigned char *npub, | 
| 178 |  |  |  |  |  |  | #     const unsigned char *k); | 
| 179 |  |  |  |  |  |  | 'crypto_aead_chacha20poly1305_ietf_encrypt' => [ | 
| 180 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'size_t', 'string', 'size_t', 'string', 'string', 'string'] => 'int', | 
| 181 |  |  |  |  |  |  | sub { | 
| 182 |  |  |  |  |  |  | my ($xsub, $msg, $ad, $nonce, $key) = @_; | 
| 183 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 184 |  |  |  |  |  |  | my $ad_len = length($ad); | 
| 185 |  |  |  |  |  |  | my $nonce_len = length($nonce); | 
| 186 |  |  |  |  |  |  | my $key_len = length($key); | 
| 187 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | unless ($nonce_len == Sodium::FFI::crypto_aead_chacha20poly1305_IETF_NPUBBYTES) { | 
| 190 |  |  |  |  |  |  | croak("Nonce length should be crypto_aead_chacha20poly1305_IETF_NPUBBYTES bytes"); | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  | unless($key_len == Sodium::FFI::crypto_aead_chacha20poly1305_IETF_KEYBYTES) { | 
| 193 |  |  |  |  |  |  | croak("Secret key length should be crypto_aead_chacha20poly1305_IETF_KEYBYTES bytes"); | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  | if ($SIZE_MAX - $msg_len <= Sodium::FFI::crypto_aead_chacha20poly1305_IETF_ABYTES) { | 
| 196 |  |  |  |  |  |  | croak("arithmetic overflow"); | 
| 197 |  |  |  |  |  |  | } | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | my $ciphertext_len = $msg_len + Sodium::FFI::crypto_aead_chacha20poly1305_IETF_ABYTES; | 
| 200 |  |  |  |  |  |  | my $ciphertext = "\0" x $ciphertext_len; | 
| 201 |  |  |  |  |  |  | my $real_len = 0; | 
| 202 |  |  |  |  |  |  | my $ret = $xsub->($ciphertext, \$real_len, $msg, $msg_len, $ad, $ad_len, undef, $nonce, $key); | 
| 203 |  |  |  |  |  |  | croak("Internal error") unless $ret == 0; | 
| 204 |  |  |  |  |  |  | if ($real_len <= 0 || $real_len > $SIZE_MAX || $real_len > $ciphertext_len) { | 
| 205 |  |  |  |  |  |  | croak("Invalid resultant length"); | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  | return substr($ciphertext, 0, $real_len); | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  | ], | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | # int | 
| 212 |  |  |  |  |  |  | # crypto_aead_chacha20poly1305_decrypt(unsigned char *m, | 
| 213 |  |  |  |  |  |  | # unsigned long long *mlen_p, | 
| 214 |  |  |  |  |  |  | # unsigned char *nsec, | 
| 215 |  |  |  |  |  |  | # const unsigned char *c, | 
| 216 |  |  |  |  |  |  | # unsigned long long clen, | 
| 217 |  |  |  |  |  |  | # const unsigned char *ad, | 
| 218 |  |  |  |  |  |  | # unsigned long long adlen, | 
| 219 |  |  |  |  |  |  | # const unsigned char *npub, | 
| 220 |  |  |  |  |  |  | # const unsigned char *k); | 
| 221 |  |  |  |  |  |  | 'crypto_aead_chacha20poly1305_decrypt' => [ | 
| 222 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'string', 'size_t', 'string', 'size_t', 'string', 'string'] => 'int', | 
| 223 |  |  |  |  |  |  | sub { | 
| 224 |  |  |  |  |  |  | my ($xsub, $ciphertext, $ad, $nonce, $key) = @_; | 
| 225 |  |  |  |  |  |  | my $ciphertext_len = length($ciphertext); | 
| 226 |  |  |  |  |  |  | my $ad_len = length($ad); | 
| 227 |  |  |  |  |  |  | my $nonce_len = length($nonce); | 
| 228 |  |  |  |  |  |  | my $key_len = length($key); | 
| 229 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | unless ($nonce_len == Sodium::FFI::crypto_aead_chacha20poly1305_NPUBBYTES) { | 
| 232 |  |  |  |  |  |  | croak("Nonce length should be crypto_aead_chacha20poly1305_NPUBBYTES bytes"); | 
| 233 |  |  |  |  |  |  | } | 
| 234 |  |  |  |  |  |  | unless($key_len == Sodium::FFI::crypto_aead_chacha20poly1305_KEYBYTES) { | 
| 235 |  |  |  |  |  |  | croak("Secret key length should be crypto_aead_chacha20poly1305_KEYBYTES bytes"); | 
| 236 |  |  |  |  |  |  | } | 
| 237 |  |  |  |  |  |  | if ($ciphertext_len < Sodium::FFI::crypto_aead_chacha20poly1305_ABYTES) { | 
| 238 |  |  |  |  |  |  | croak("cipher text length not right"); | 
| 239 |  |  |  |  |  |  | } | 
| 240 |  |  |  |  |  |  | my $msg_len = $ciphertext_len; | 
| 241 |  |  |  |  |  |  | if ($msg_len > $SIZE_MAX) { | 
| 242 |  |  |  |  |  |  | croak("Message length greater than max size"); | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  | my $msg = "\0" x $msg_len; | 
| 245 |  |  |  |  |  |  | my $real_len = 0; | 
| 246 |  |  |  |  |  |  | my $ret = $xsub->($msg, \$real_len, undef, $ciphertext, $ciphertext_len, $ad, $ad_len, $nonce, $key); | 
| 247 |  |  |  |  |  |  | croak("Internal error") unless $ret == 0; | 
| 248 |  |  |  |  |  |  | if ($real_len <= 0 || $real_len >= $SIZE_MAX || $real_len > $msg_len) { | 
| 249 |  |  |  |  |  |  | croak("Invalid resultant length"); | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  | if ($real_len >= $SIZE_MAX || $real_len > $msg_len) { | 
| 252 |  |  |  |  |  |  | croak("arithmetic overflow"); | 
| 253 |  |  |  |  |  |  | } | 
| 254 |  |  |  |  |  |  | return substr($msg, 0, $real_len); | 
| 255 |  |  |  |  |  |  | } | 
| 256 |  |  |  |  |  |  | ], | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | # int | 
| 259 |  |  |  |  |  |  | # crypto_aead_chacha20poly1305_encrypt(unsigned char *c, | 
| 260 |  |  |  |  |  |  | #     unsigned long long *clen_p, | 
| 261 |  |  |  |  |  |  | #     const unsigned char *m, | 
| 262 |  |  |  |  |  |  | #     unsigned long long mlen, | 
| 263 |  |  |  |  |  |  | #     const unsigned char *ad, | 
| 264 |  |  |  |  |  |  | #     unsigned long long adlen, | 
| 265 |  |  |  |  |  |  | #     const unsigned char *nsec, | 
| 266 |  |  |  |  |  |  | #     const unsigned char *npub, | 
| 267 |  |  |  |  |  |  | #     const unsigned char *k) | 
| 268 |  |  |  |  |  |  | 'crypto_aead_chacha20poly1305_encrypt' => [ | 
| 269 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'size_t', 'string', 'size_t', 'string', 'string', 'string'] => 'int', | 
| 270 |  |  |  |  |  |  | sub { | 
| 271 |  |  |  |  |  |  | my ($xsub, $msg, $ad, $nonce, $key) = @_; | 
| 272 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 273 |  |  |  |  |  |  | my $ad_len = length($ad); | 
| 274 |  |  |  |  |  |  | my $nonce_len = length($nonce); | 
| 275 |  |  |  |  |  |  | my $key_len = length($key); | 
| 276 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | unless ($nonce_len == Sodium::FFI::crypto_aead_chacha20poly1305_NPUBBYTES) { | 
| 279 |  |  |  |  |  |  | croak("Nonce length should be crypto_aead_chacha20poly1305_NPUBBYTES bytes"); | 
| 280 |  |  |  |  |  |  | } | 
| 281 |  |  |  |  |  |  | unless($key_len == Sodium::FFI::crypto_aead_chacha20poly1305_KEYBYTES) { | 
| 282 |  |  |  |  |  |  | croak("Secret key length should be crypto_aead_chacha20poly1305_KEYBYTES bytes"); | 
| 283 |  |  |  |  |  |  | } | 
| 284 |  |  |  |  |  |  | if ($SIZE_MAX - $msg_len <= Sodium::FFI::crypto_aead_chacha20poly1305_ABYTES) { | 
| 285 |  |  |  |  |  |  | croak("arithmetic overflow"); | 
| 286 |  |  |  |  |  |  | } | 
| 287 |  |  |  |  |  |  |  | 
| 288 |  |  |  |  |  |  | my $ciphertext_len = $msg_len + Sodium::FFI::crypto_aead_chacha20poly1305_ABYTES; | 
| 289 |  |  |  |  |  |  | my $ciphertext = "\0" x $ciphertext_len; | 
| 290 |  |  |  |  |  |  | my $real_len = 0; | 
| 291 |  |  |  |  |  |  | my $ret = $xsub->($ciphertext, \$real_len, $msg, $msg_len, $ad, $ad_len, undef, $nonce, $key); | 
| 292 |  |  |  |  |  |  | croak("Internal error") unless $ret == 0; | 
| 293 |  |  |  |  |  |  | if ($real_len <= 0 || $real_len > $SIZE_MAX || $real_len > $ciphertext_len) { | 
| 294 |  |  |  |  |  |  | croak("Invalid resultant length"); | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  | return substr($ciphertext, 0, $real_len); | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  | ], | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | # int | 
| 301 |  |  |  |  |  |  | # crypto_aead_aes256gcm_encrypt(unsigned char *c, | 
| 302 |  |  |  |  |  |  | # unsigned long long *clen_p, | 
| 303 |  |  |  |  |  |  | # const unsigned char *m, | 
| 304 |  |  |  |  |  |  | # unsigned long long mlen, | 
| 305 |  |  |  |  |  |  | # const unsigned char *ad, | 
| 306 |  |  |  |  |  |  | # unsigned long long adlen, | 
| 307 |  |  |  |  |  |  | # const unsigned char *nsec, | 
| 308 |  |  |  |  |  |  | # const unsigned char *npub, | 
| 309 |  |  |  |  |  |  | # const unsigned char *k); | 
| 310 |  |  |  |  |  |  | 'crypto_aead_aes256gcm_encrypt' => [ | 
| 311 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'size_t', 'string', 'size_t', 'string', 'string', 'string'] => 'int', | 
| 312 |  |  |  |  |  |  | sub { | 
| 313 |  |  |  |  |  |  | my ($xsub, $msg, $ad, $nonce, $key) = @_; | 
| 314 |  |  |  |  |  |  | croak("AESGCM not available.") unless Sodium::FFI::crypto_aead_aes256gcm_is_available(); | 
| 315 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 316 |  |  |  |  |  |  | my $ad_len = length($ad); | 
| 317 |  |  |  |  |  |  | my $nonce_len = length($nonce); | 
| 318 |  |  |  |  |  |  | my $key_len = length($key); | 
| 319 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | unless ($nonce_len == Sodium::FFI::crypto_aead_aes256gcm_NPUBBYTES) { | 
| 322 |  |  |  |  |  |  | croak("Nonce length should be crypto_aead_aes256gcm_NPUBBYTES bytes"); | 
| 323 |  |  |  |  |  |  | } | 
| 324 |  |  |  |  |  |  | unless($key_len == Sodium::FFI::crypto_aead_aes256gcm_KEYBYTES) { | 
| 325 |  |  |  |  |  |  | croak("Secret key length should be crypto_aead_aes256gcm_KEYBYTES bytes"); | 
| 326 |  |  |  |  |  |  | } | 
| 327 |  |  |  |  |  |  | if ($SIZE_MAX - $msg_len <= Sodium::FFI::crypto_aead_aes256gcm_ABYTES) { | 
| 328 |  |  |  |  |  |  | croak("arithmetic overflow"); | 
| 329 |  |  |  |  |  |  | } | 
| 330 |  |  |  |  |  |  | if ($msg_len > (16 * ((1 << 32) - 2)) - Sodium::FFI::crypto_aead_aes256gcm_ABYTES) { | 
| 331 |  |  |  |  |  |  | croak("message too long for a single key"); | 
| 332 |  |  |  |  |  |  | } | 
| 333 |  |  |  |  |  |  | my $ciphertext_len = $msg_len + Sodium::FFI::crypto_aead_aes256gcm_ABYTES; | 
| 334 |  |  |  |  |  |  | my $ciphertext = "\0" x $ciphertext_len; | 
| 335 |  |  |  |  |  |  | my $real_len = 0; | 
| 336 |  |  |  |  |  |  | my $ret = $xsub->($ciphertext, \$real_len, $msg, $msg_len, $ad, $ad_len, undef, $nonce, $key); | 
| 337 |  |  |  |  |  |  | croak("Internal error") unless $ret == 0; | 
| 338 |  |  |  |  |  |  | if ($real_len <= 0 || $real_len > $SIZE_MAX || $real_len > $ciphertext_len) { | 
| 339 |  |  |  |  |  |  | croak("Invalid resultant length"); | 
| 340 |  |  |  |  |  |  | } | 
| 341 |  |  |  |  |  |  | return substr($ciphertext, 0, $real_len); | 
| 342 |  |  |  |  |  |  | } | 
| 343 |  |  |  |  |  |  | ], | 
| 344 |  |  |  |  |  |  |  | 
| 345 |  |  |  |  |  |  | # int | 
| 346 |  |  |  |  |  |  | # crypto_aead_aes256gcm_decrypt(unsigned char *m, | 
| 347 |  |  |  |  |  |  | # unsigned long long *mlen_p, | 
| 348 |  |  |  |  |  |  | # unsigned char *nsec, | 
| 349 |  |  |  |  |  |  | # const unsigned char *c, | 
| 350 |  |  |  |  |  |  | # unsigned long long clen, | 
| 351 |  |  |  |  |  |  | # const unsigned char *ad, | 
| 352 |  |  |  |  |  |  | # unsigned long long adlen, | 
| 353 |  |  |  |  |  |  | # const unsigned char *npub, | 
| 354 |  |  |  |  |  |  | # const unsigned char *k); | 
| 355 |  |  |  |  |  |  | 'crypto_aead_aes256gcm_decrypt' => [ | 
| 356 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'string', 'size_t', 'string', 'size_t', 'string', 'string'] => 'int', | 
| 357 |  |  |  |  |  |  | sub { | 
| 358 |  |  |  |  |  |  | my ($xsub, $ciphertext, $ad, $nonce, $key) = @_; | 
| 359 |  |  |  |  |  |  | croak("AESGCM not available.") unless Sodium::FFI::crypto_aead_aes256gcm_is_available(); | 
| 360 |  |  |  |  |  |  | my $ciphertext_len = length($ciphertext); | 
| 361 |  |  |  |  |  |  | my $ad_len = length($ad); | 
| 362 |  |  |  |  |  |  | my $nonce_len = length($nonce); | 
| 363 |  |  |  |  |  |  | my $key_len = length($key); | 
| 364 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | unless ($nonce_len == Sodium::FFI::crypto_aead_aes256gcm_NPUBBYTES) { | 
| 367 |  |  |  |  |  |  | croak("Nonce length should be crypto_aead_aes256gcm_NPUBBYTES bytes"); | 
| 368 |  |  |  |  |  |  | } | 
| 369 |  |  |  |  |  |  | unless($key_len == Sodium::FFI::crypto_aead_aes256gcm_KEYBYTES) { | 
| 370 |  |  |  |  |  |  | croak("Secret key length should be crypto_aead_aes256gcm_KEYBYTES bytes"); | 
| 371 |  |  |  |  |  |  | } | 
| 372 |  |  |  |  |  |  | if ($ciphertext_len < Sodium::FFI::crypto_aead_aes256gcm_ABYTES) { | 
| 373 |  |  |  |  |  |  | croak("cipher text length not right"); | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  | if ($ciphertext_len - Sodium::FFI::crypto_aead_aes256gcm_ABYTES > 16 * ((1 << 32) - 2)) { | 
| 376 |  |  |  |  |  |  | croak("cipher text too long for a single key"); | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  | my $msg_len = $ciphertext_len; | 
| 379 |  |  |  |  |  |  | if ($msg_len > $SIZE_MAX) { | 
| 380 |  |  |  |  |  |  | croak("Message length greater than max size"); | 
| 381 |  |  |  |  |  |  | } | 
| 382 |  |  |  |  |  |  | my $msg = "\0" x $msg_len; | 
| 383 |  |  |  |  |  |  | my $real_len = 0; | 
| 384 |  |  |  |  |  |  | my $ret = $xsub->($msg, \$real_len, undef, $ciphertext, $ciphertext_len, $ad, $ad_len, $nonce, $key); | 
| 385 |  |  |  |  |  |  | croak("Internal error") unless $ret == 0; | 
| 386 |  |  |  |  |  |  | if ($real_len <= 0 || $real_len >= $SIZE_MAX || $real_len > $msg_len) { | 
| 387 |  |  |  |  |  |  | croak("Invalid resultant length"); | 
| 388 |  |  |  |  |  |  | } | 
| 389 |  |  |  |  |  |  | return substr($msg, 0, $real_len); | 
| 390 |  |  |  |  |  |  | } | 
| 391 |  |  |  |  |  |  | ], | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | # int | 
| 394 |  |  |  |  |  |  | # crypto_aead_aes256gcm_is_available() | 
| 395 |  |  |  |  |  |  | 'crypto_aead_aes256gcm_is_available' => [ | 
| 396 |  |  |  |  |  |  | [] => 'int', | 
| 397 |  |  |  |  |  |  | sub { | 
| 398 |  |  |  |  |  |  | my ($xsub) = @_; | 
| 399 |  |  |  |  |  |  | if (Sodium::FFI::HAVE_AESGCM) { | 
| 400 |  |  |  |  |  |  | return $xsub->(); | 
| 401 |  |  |  |  |  |  | } | 
| 402 |  |  |  |  |  |  | return 0; | 
| 403 |  |  |  |  |  |  | } | 
| 404 |  |  |  |  |  |  | ], | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | # int | 
| 407 |  |  |  |  |  |  | # crypto_box_easy(unsigned char *c, const unsigned char *m, | 
| 408 |  |  |  |  |  |  | #   unsigned long long mlen, const unsigned char *n, | 
| 409 |  |  |  |  |  |  | #   const unsigned char *pk, const unsigned char *sk); | 
| 410 |  |  |  |  |  |  | 'crypto_box_easy' => [ | 
| 411 |  |  |  |  |  |  | ['string', 'string', 'size_t', 'string', 'string', 'string'] => 'int', | 
| 412 |  |  |  |  |  |  | sub { | 
| 413 |  |  |  |  |  |  | my ($xsub, $msg, $nonce, $pk, $sk) = @_; | 
| 414 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 415 |  |  |  |  |  |  | my $nonce_len = length($nonce); | 
| 416 |  |  |  |  |  |  | my $pk_len = length($pk); | 
| 417 |  |  |  |  |  |  | my $sk_len = length($sk); | 
| 418 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 419 |  |  |  |  |  |  | if ($nonce_len != Sodium::FFI::crypto_box_NONCEBYTES) { | 
| 420 |  |  |  |  |  |  | croak("The nonce must be crypto_box_NONCEBYTES in length"); | 
| 421 |  |  |  |  |  |  | } | 
| 422 |  |  |  |  |  |  | if ($pk_len != Sodium::FFI::crypto_box_PUBLICKEYBYTES) { | 
| 423 |  |  |  |  |  |  | croak("The public key must be crypto_box_PUBLICKEYBYTES in length"); | 
| 424 |  |  |  |  |  |  | } | 
| 425 |  |  |  |  |  |  | if ($sk_len != Sodium::FFI::crypto_box_SECRETKEYBYTES) { | 
| 426 |  |  |  |  |  |  | croak("The secret key must be crypto_box_SECRETKEYBYTES in length"); | 
| 427 |  |  |  |  |  |  | } | 
| 428 |  |  |  |  |  |  | if ($SIZE_MAX - $msg_len <= Sodium::FFI::crypto_box_MACBYTES) { | 
| 429 |  |  |  |  |  |  | croak("Arithmetic overflow"); | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  | my $cipher_len = Sodium::FFI::crypto_box_MACBYTES + $msg_len; | 
| 432 |  |  |  |  |  |  | my $cipher_text = "\0" x $cipher_len; | 
| 433 |  |  |  |  |  |  | my $ret = $xsub->($cipher_text, $msg, $msg_len, $nonce, $pk, $sk); | 
| 434 |  |  |  |  |  |  | if ($ret != 0) { | 
| 435 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 436 |  |  |  |  |  |  | } | 
| 437 |  |  |  |  |  |  | return $cipher_text; | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  | ], | 
| 440 |  |  |  |  |  |  |  | 
| 441 |  |  |  |  |  |  | # int | 
| 442 |  |  |  |  |  |  | # crypto_box_keypair(unsigned char *pk, unsigned char *sk); | 
| 443 |  |  |  |  |  |  | 'crypto_box_keypair' => [ | 
| 444 |  |  |  |  |  |  | ['string', 'string'] => 'int', | 
| 445 |  |  |  |  |  |  | sub { | 
| 446 |  |  |  |  |  |  | my ($xsub) = @_; | 
| 447 |  |  |  |  |  |  | my $pubkey = "\0" x Sodium::FFI::crypto_box_PUBLICKEYBYTES ; | 
| 448 |  |  |  |  |  |  | my $seckey = "\0" x Sodium::FFI::crypto_box_SECRETKEYBYTES; | 
| 449 |  |  |  |  |  |  | my $ret = $xsub->($pubkey, $seckey); | 
| 450 |  |  |  |  |  |  | if ($ret != 0) { | 
| 451 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 452 |  |  |  |  |  |  | } | 
| 453 |  |  |  |  |  |  | return ($pubkey, $seckey); | 
| 454 |  |  |  |  |  |  | } | 
| 455 |  |  |  |  |  |  | ], | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | # int | 
| 458 |  |  |  |  |  |  | # crypto_box_open_easy(unsigned char *m, const unsigned char *c, | 
| 459 |  |  |  |  |  |  | #   unsigned long long clen, const unsigned char *n, | 
| 460 |  |  |  |  |  |  | #   const unsigned char *pk, const unsigned char *sk); | 
| 461 |  |  |  |  |  |  | 'crypto_box_open_easy' => [ | 
| 462 |  |  |  |  |  |  | ['string', 'string', 'size_t', 'string', 'string', 'string'] => 'int', | 
| 463 |  |  |  |  |  |  | sub { | 
| 464 |  |  |  |  |  |  | my ($xsub, $cipher_text, $nonce, $pk, $sk) = @_; | 
| 465 |  |  |  |  |  |  | my $cipher_len = length($cipher_text); | 
| 466 |  |  |  |  |  |  | my $nonce_len = length($nonce); | 
| 467 |  |  |  |  |  |  | my $pk_len = length($pk); | 
| 468 |  |  |  |  |  |  | my $sk_len = length($sk); | 
| 469 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 470 |  |  |  |  |  |  | if ($nonce_len != Sodium::FFI::crypto_box_NONCEBYTES) { | 
| 471 |  |  |  |  |  |  | croak("The nonce must be crypto_box_NONCEBYTES in length"); | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  | if ($pk_len != Sodium::FFI::crypto_box_PUBLICKEYBYTES) { | 
| 474 |  |  |  |  |  |  | croak("The public key must be crypto_box_PUBLICKEYBYTES in length"); | 
| 475 |  |  |  |  |  |  | } | 
| 476 |  |  |  |  |  |  | if ($sk_len != Sodium::FFI::crypto_box_SECRETKEYBYTES) { | 
| 477 |  |  |  |  |  |  | croak("The secret key must be crypto_box_SECRETKEYBYTES in length"); | 
| 478 |  |  |  |  |  |  | } | 
| 479 |  |  |  |  |  |  | if ($cipher_len <= Sodium::FFI::crypto_box_MACBYTES) { | 
| 480 |  |  |  |  |  |  | croak("The cipher text should be larger than crypto_box_MACBYTES bytes"); | 
| 481 |  |  |  |  |  |  | } | 
| 482 |  |  |  |  |  |  |  | 
| 483 |  |  |  |  |  |  | my $msg_len = $cipher_len - Sodium::FFI::crypto_box_MACBYTES; | 
| 484 |  |  |  |  |  |  | my $msg = "\0" x $msg_len; | 
| 485 |  |  |  |  |  |  | my $ret = $xsub->($msg, $cipher_text, $cipher_len, $nonce, $pk, $sk); | 
| 486 |  |  |  |  |  |  | if ($ret != 0) { | 
| 487 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 488 |  |  |  |  |  |  | } | 
| 489 |  |  |  |  |  |  | return $msg; | 
| 490 |  |  |  |  |  |  | } | 
| 491 |  |  |  |  |  |  | ], | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | # int | 
| 494 |  |  |  |  |  |  | # crypto_box_seal(unsigned char *c, const unsigned char *m, | 
| 495 |  |  |  |  |  |  | #               unsigned long long mlen, const unsigned char *pk) | 
| 496 |  |  |  |  |  |  | 'crypto_box_seal' => [ | 
| 497 |  |  |  |  |  |  | ['string', 'string', 'size_t', 'string'] => 'int', | 
| 498 |  |  |  |  |  |  | sub { | 
| 499 |  |  |  |  |  |  | my ($xsub, $message, $pk) = @_; | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | if (length($pk) != Sodium::FFI::crypto_box_PUBLICKEYBYTES) { | 
| 502 |  |  |  |  |  |  | croak( | 
| 503 |  |  |  |  |  |  | "The public key must be crypto_box_PUBLICKEYBYTES in length" | 
| 504 |  |  |  |  |  |  | ); | 
| 505 |  |  |  |  |  |  | } | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | my $message_len = length($message); | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | my $cipher_len  = Sodium::FFI::crypto_box_SEALBYTES + $message_len; | 
| 510 |  |  |  |  |  |  | my $cipher_text = "\0" x $cipher_len; | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | my $ret = $xsub->($cipher_text, $message, $message_len, $pk); | 
| 513 |  |  |  |  |  |  | if ($ret != 0) { | 
| 514 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 515 |  |  |  |  |  |  | } | 
| 516 |  |  |  |  |  |  | return $cipher_text; | 
| 517 |  |  |  |  |  |  | } | 
| 518 |  |  |  |  |  |  | ], | 
| 519 |  |  |  |  |  |  |  | 
| 520 |  |  |  |  |  |  | # crypto_box_seal_open(unsigned char *m, const unsigned char *c, | 
| 521 |  |  |  |  |  |  | #               unsigned long long clen, | 
| 522 |  |  |  |  |  |  | #               const unsigned char *pk, const unsigned char *sk) | 
| 523 |  |  |  |  |  |  | 'crypto_box_seal_open' => [ | 
| 524 |  |  |  |  |  |  | ['string', 'string', 'size_t', 'string', 'string'] => 'int', | 
| 525 |  |  |  |  |  |  | sub { | 
| 526 |  |  |  |  |  |  | my ($xsub, $cipher_text, $pk, $sk) = @_; | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  | if (length($pk) != Sodium::FFI::crypto_box_PUBLICKEYBYTES) { | 
| 529 |  |  |  |  |  |  | croak( | 
| 530 |  |  |  |  |  |  | "The public key must be crypto_box_PUBLICKEYBYTES in length" | 
| 531 |  |  |  |  |  |  | ); | 
| 532 |  |  |  |  |  |  | } | 
| 533 |  |  |  |  |  |  | if (length($sk) != Sodium::FFI::crypto_box_SECRETKEYBYTES) { | 
| 534 |  |  |  |  |  |  | croak( | 
| 535 |  |  |  |  |  |  | "The secret key must be crypto_box_SECRETKEYBYTES in length" | 
| 536 |  |  |  |  |  |  | ); | 
| 537 |  |  |  |  |  |  | } | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | if (length($cipher_text) < crypto_box_SEALBYTES) { | 
| 540 |  |  |  |  |  |  | return -1; | 
| 541 |  |  |  |  |  |  | } | 
| 542 |  |  |  |  |  |  |  | 
| 543 |  |  |  |  |  |  | my $msg = "\0" x (length($cipher_text) - crypto_box_SEALBYTES); | 
| 544 |  |  |  |  |  |  | my $ret | 
| 545 |  |  |  |  |  |  | = $xsub->($msg, $cipher_text, length($cipher_text), $pk, $sk); | 
| 546 |  |  |  |  |  |  | if ($ret != 0) { | 
| 547 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 548 |  |  |  |  |  |  | } | 
| 549 |  |  |  |  |  |  | return $msg; | 
| 550 |  |  |  |  |  |  | } | 
| 551 |  |  |  |  |  |  | ], | 
| 552 |  |  |  |  |  |  |  | 
| 553 |  |  |  |  |  |  | # int | 
| 554 |  |  |  |  |  |  | # crypto_box_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed); | 
| 555 |  |  |  |  |  |  | 'crypto_box_seed_keypair' => [ | 
| 556 |  |  |  |  |  |  | ['string', 'string', 'string'] => 'int', | 
| 557 |  |  |  |  |  |  | sub { | 
| 558 |  |  |  |  |  |  | my ($xsub, $seed) = @_; | 
| 559 |  |  |  |  |  |  | my $seed_len = length($seed); | 
| 560 |  |  |  |  |  |  | unless ($seed_len == Sodium::FFI::crypto_box_SEEDBYTES) { | 
| 561 |  |  |  |  |  |  | croak("Seed length must be crypto_box_SEEDBYTES in length"); | 
| 562 |  |  |  |  |  |  | } | 
| 563 |  |  |  |  |  |  | my $pubkey = "\0" x Sodium::FFI::crypto_box_PUBLICKEYBYTES; | 
| 564 |  |  |  |  |  |  | my $seckey = "\0" x Sodium::FFI::crypto_box_SECRETKEYBYTES; | 
| 565 |  |  |  |  |  |  | my $ret = $xsub->($pubkey, $seckey, $seed); | 
| 566 |  |  |  |  |  |  | if ($ret != 0) { | 
| 567 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 568 |  |  |  |  |  |  | } | 
| 569 |  |  |  |  |  |  | return ($pubkey, $seckey); | 
| 570 |  |  |  |  |  |  | } | 
| 571 |  |  |  |  |  |  | ], | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | # int | 
| 574 |  |  |  |  |  |  | # crypto_scalarmult_base(unsigned char *q, const unsigned char *n); | 
| 575 |  |  |  |  |  |  | 'crypto_scalarmult_base' => [ | 
| 576 |  |  |  |  |  |  | ['string', 'string'] => 'int', | 
| 577 |  |  |  |  |  |  | sub { | 
| 578 |  |  |  |  |  |  | my ($xsub, $secret_key) = @_; | 
| 579 |  |  |  |  |  |  | my $sk_len = length($secret_key); | 
| 580 |  |  |  |  |  |  | unless ($sk_len == Sodium::FFI::crypto_box_SECRETKEYBYTES) { | 
| 581 |  |  |  |  |  |  | croak("Secret Key length must be crypto_box_SECRETKEYBYTES in length"); | 
| 582 |  |  |  |  |  |  | } | 
| 583 |  |  |  |  |  |  | my $pubkey = "\0" x Sodium::FFI::crypto_box_PUBLICKEYBYTES; | 
| 584 |  |  |  |  |  |  | my $ret = $xsub->($pubkey, $secret_key); | 
| 585 |  |  |  |  |  |  | if ($ret != 0) { | 
| 586 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 587 |  |  |  |  |  |  | } | 
| 588 |  |  |  |  |  |  | return $pubkey; | 
| 589 |  |  |  |  |  |  | } | 
| 590 |  |  |  |  |  |  | ], | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | # int | 
| 593 |  |  |  |  |  |  | # crypto_sign_keypair(unsigned char *pk, unsigned char *sk); | 
| 594 |  |  |  |  |  |  | 'crypto_sign_keypair' => [ | 
| 595 |  |  |  |  |  |  | ['string', 'string'] => 'int', | 
| 596 |  |  |  |  |  |  | sub { | 
| 597 |  |  |  |  |  |  | my ($xsub) = @_; | 
| 598 |  |  |  |  |  |  | my $pubkey = "\0" x Sodium::FFI::crypto_sign_PUBLICKEYBYTES; | 
| 599 |  |  |  |  |  |  | my $seckey = "\0" x Sodium::FFI::crypto_sign_SECRETKEYBYTES; | 
| 600 |  |  |  |  |  |  | my $ret = $xsub->($pubkey, $seckey); | 
| 601 |  |  |  |  |  |  | if ($ret != 0) { | 
| 602 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 603 |  |  |  |  |  |  | } | 
| 604 |  |  |  |  |  |  | return ($pubkey, $seckey); | 
| 605 |  |  |  |  |  |  | } | 
| 606 |  |  |  |  |  |  | ], | 
| 607 |  |  |  |  |  |  |  | 
| 608 |  |  |  |  |  |  | # int | 
| 609 |  |  |  |  |  |  | # crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed); | 
| 610 |  |  |  |  |  |  | 'crypto_sign_seed_keypair' => [ | 
| 611 |  |  |  |  |  |  | ['string', 'string', 'string'] => 'int', | 
| 612 |  |  |  |  |  |  | sub { | 
| 613 |  |  |  |  |  |  | my ($xsub, $seed) = @_; | 
| 614 |  |  |  |  |  |  | my $seed_len = length($seed); | 
| 615 |  |  |  |  |  |  | unless ($seed_len == Sodium::FFI::crypto_sign_SEEDBYTES) { | 
| 616 |  |  |  |  |  |  | croak("Seed length must be crypto_sign_SEEDBYTES in length"); | 
| 617 |  |  |  |  |  |  | } | 
| 618 |  |  |  |  |  |  | my $pubkey = "\0" x Sodium::FFI::crypto_sign_PUBLICKEYBYTES; | 
| 619 |  |  |  |  |  |  | my $seckey = "\0" x Sodium::FFI::crypto_sign_SECRETKEYBYTES; | 
| 620 |  |  |  |  |  |  | my $ret = $xsub->($pubkey, $seckey, $seed); | 
| 621 |  |  |  |  |  |  | if ($ret != 0) { | 
| 622 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 623 |  |  |  |  |  |  | } | 
| 624 |  |  |  |  |  |  | return ($pubkey, $seckey); | 
| 625 |  |  |  |  |  |  | } | 
| 626 |  |  |  |  |  |  | ], | 
| 627 |  |  |  |  |  |  |  | 
| 628 |  |  |  |  |  |  | # int | 
| 629 |  |  |  |  |  |  | # crypto_sign(unsigned char *sm, unsigned long long *smlen_p, | 
| 630 |  |  |  |  |  |  | #     const unsigned char *m, unsigned long long mlen, | 
| 631 |  |  |  |  |  |  | #     const unsigned char *sk); | 
| 632 |  |  |  |  |  |  | 'crypto_sign' => [ | 
| 633 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'size_t', 'string'] => 'int', | 
| 634 |  |  |  |  |  |  | sub { | 
| 635 |  |  |  |  |  |  | my ($xsub, $msg, $key) = @_; | 
| 636 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 637 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 638 |  |  |  |  |  |  | my $key_len = length($key); | 
| 639 |  |  |  |  |  |  | unless ($key_len == Sodium::FFI::crypto_sign_SECRETKEYBYTES) { | 
| 640 |  |  |  |  |  |  | croak("Secret Key length must be crypto_sign_SECRETKEYBYTES in length"); | 
| 641 |  |  |  |  |  |  | } | 
| 642 |  |  |  |  |  |  | if ($SIZE_MAX - $msg_len <= Sodium::FFI::crypto_sign_BYTES) { | 
| 643 |  |  |  |  |  |  | croak("Arithmetic overflow"); | 
| 644 |  |  |  |  |  |  | } | 
| 645 |  |  |  |  |  |  | my $real_len = 0; | 
| 646 |  |  |  |  |  |  | my $signed_len = $msg_len + Sodium::FFI::crypto_sign_BYTES; | 
| 647 |  |  |  |  |  |  | my $signed = "\0" x $signed_len; | 
| 648 |  |  |  |  |  |  | my $ret = $xsub->($signed, \$real_len, $msg, $msg_len, $key); | 
| 649 |  |  |  |  |  |  | if ($ret != 0) { | 
| 650 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 651 |  |  |  |  |  |  | } | 
| 652 |  |  |  |  |  |  | if ($real_len >= $SIZE_MAX || $real_len > $signed_len) { | 
| 653 |  |  |  |  |  |  | croak("Arithmetic overflow"); | 
| 654 |  |  |  |  |  |  | } | 
| 655 |  |  |  |  |  |  | return substr($signed, 0, $real_len); | 
| 656 |  |  |  |  |  |  | } | 
| 657 |  |  |  |  |  |  | ], | 
| 658 |  |  |  |  |  |  |  | 
| 659 |  |  |  |  |  |  | # int | 
| 660 |  |  |  |  |  |  | # crypto_sign_detached(unsigned char *sig, unsigned long long *siglen_p, | 
| 661 |  |  |  |  |  |  | #     const unsigned char *m, unsigned long long mlen, | 
| 662 |  |  |  |  |  |  | #     const unsigned char *sk); | 
| 663 |  |  |  |  |  |  | 'crypto_sign_detached' => [ | 
| 664 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'size_t', 'string'] => 'int', | 
| 665 |  |  |  |  |  |  | sub { | 
| 666 |  |  |  |  |  |  | my ($xsub, $msg, $key) = @_; | 
| 667 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 668 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 669 |  |  |  |  |  |  | my $key_len = length($key); | 
| 670 |  |  |  |  |  |  | unless ($key_len == Sodium::FFI::crypto_sign_SECRETKEYBYTES) { | 
| 671 |  |  |  |  |  |  | croak("Secret Key length must be crypto_sign_SECRETKEYBYTES in length"); | 
| 672 |  |  |  |  |  |  | } | 
| 673 |  |  |  |  |  |  | my $signature = "\0" x Sodium::FFI::crypto_sign_BYTES; | 
| 674 |  |  |  |  |  |  | my $real_len = 0; | 
| 675 |  |  |  |  |  |  | my $ret = $xsub->($signature, \$real_len, $msg, $msg_len, $key); | 
| 676 |  |  |  |  |  |  | if ($ret != 0) { | 
| 677 |  |  |  |  |  |  | croak("Signature creation failed."); | 
| 678 |  |  |  |  |  |  | } | 
| 679 |  |  |  |  |  |  | if ($real_len <= 0 || $real_len > Sodium::FFI::crypto_sign_BYTES) { | 
| 680 |  |  |  |  |  |  | croak("Signature size isn't correct."); | 
| 681 |  |  |  |  |  |  | } | 
| 682 |  |  |  |  |  |  | return substr($signature, 0, $real_len); | 
| 683 |  |  |  |  |  |  | } | 
| 684 |  |  |  |  |  |  | ], | 
| 685 |  |  |  |  |  |  |  | 
| 686 |  |  |  |  |  |  | # int | 
| 687 |  |  |  |  |  |  | # crypto_sign_open(unsigned char *m, unsigned long long *mlen_p, | 
| 688 |  |  |  |  |  |  | #     const unsigned char *sm, unsigned long long smlen, | 
| 689 |  |  |  |  |  |  | #     const unsigned char *pk); | 
| 690 |  |  |  |  |  |  | 'crypto_sign_open' => [ | 
| 691 |  |  |  |  |  |  | ['string', 'size_t*', 'string', 'size_t', 'string'] => 'int', | 
| 692 |  |  |  |  |  |  | sub { | 
| 693 |  |  |  |  |  |  | my ($xsub, $msg, $key) = @_; | 
| 694 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 695 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 696 |  |  |  |  |  |  | my $key_len = length($key); | 
| 697 |  |  |  |  |  |  | unless ($key_len == Sodium::FFI::crypto_sign_PUBLICKEYBYTES) { | 
| 698 |  |  |  |  |  |  | croak("Public Key length must be crypto_sign_PUBLICKEYBYTES in length"); | 
| 699 |  |  |  |  |  |  | } | 
| 700 |  |  |  |  |  |  | if ($SIZE_MAX - $msg_len <= Sodium::FFI::crypto_sign_BYTES) { | 
| 701 |  |  |  |  |  |  | croak("Arithmetic overflow"); | 
| 702 |  |  |  |  |  |  | } | 
| 703 |  |  |  |  |  |  | my $real_len = 0; | 
| 704 |  |  |  |  |  |  | my $open = "\0" x $msg_len; | 
| 705 |  |  |  |  |  |  | my $ret = $xsub->($open, \$real_len, $msg, $msg_len, $key); | 
| 706 |  |  |  |  |  |  | if ($ret != 0) { | 
| 707 |  |  |  |  |  |  | croak("Some internal error happened"); | 
| 708 |  |  |  |  |  |  | } | 
| 709 |  |  |  |  |  |  | if ($real_len >= $SIZE_MAX || $real_len > $msg_len) { | 
| 710 |  |  |  |  |  |  | croak("Arithmetic overflow"); | 
| 711 |  |  |  |  |  |  | } | 
| 712 |  |  |  |  |  |  | return substr($open, 0, $real_len); | 
| 713 |  |  |  |  |  |  | } | 
| 714 |  |  |  |  |  |  | ], | 
| 715 |  |  |  |  |  |  |  | 
| 716 |  |  |  |  |  |  | # int | 
| 717 |  |  |  |  |  |  | # crypto_sign_verify_detached(const unsigned char *sig, | 
| 718 |  |  |  |  |  |  | #     const unsigned char *m, | 
| 719 |  |  |  |  |  |  | #     unsigned long long mlen, | 
| 720 |  |  |  |  |  |  | #     const unsigned char *pk); | 
| 721 |  |  |  |  |  |  | 'crypto_sign_verify_detached' => [ | 
| 722 |  |  |  |  |  |  | ['string', 'string', 'size_t', 'string'] => 'int', | 
| 723 |  |  |  |  |  |  | sub { | 
| 724 |  |  |  |  |  |  | my ($xsub, $sig, $msg, $key) = @_; | 
| 725 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 726 |  |  |  |  |  |  | my $sig_len = length($sig); | 
| 727 |  |  |  |  |  |  | my $msg_len = length($msg); | 
| 728 |  |  |  |  |  |  | my $key_len = length($key); | 
| 729 |  |  |  |  |  |  | unless ($sig_len == Sodium::FFI::crypto_sign_BYTES) { | 
| 730 |  |  |  |  |  |  | croak("Signature length must be crypto_sign_BYTES in length"); | 
| 731 |  |  |  |  |  |  | } | 
| 732 |  |  |  |  |  |  | unless ($key_len == Sodium::FFI::crypto_sign_PUBLICKEYBYTES) { | 
| 733 |  |  |  |  |  |  | croak("Public Key length must be crypto_sign_PUBLICKEYBYTES in length"); | 
| 734 |  |  |  |  |  |  | } | 
| 735 |  |  |  |  |  |  | my $ret = $xsub->($sig, $msg, $msg_len, $key); | 
| 736 |  |  |  |  |  |  | return 1 if ($ret == 0); | 
| 737 |  |  |  |  |  |  | return 0; | 
| 738 |  |  |  |  |  |  | } | 
| 739 |  |  |  |  |  |  | ], | 
| 740 |  |  |  |  |  |  |  | 
| 741 |  |  |  |  |  |  | # void | 
| 742 |  |  |  |  |  |  | # randombytes_buf(void * const buf, const size_t size) | 
| 743 |  |  |  |  |  |  | 'randombytes_buf' => [ | 
| 744 |  |  |  |  |  |  | ['string', 'size_t'] => 'void', | 
| 745 |  |  |  |  |  |  | sub { | 
| 746 |  |  |  |  |  |  | my ($xsub, $len) = @_; | 
| 747 |  |  |  |  |  |  | $len //= 0; | 
| 748 |  |  |  |  |  |  | return '' unless $len > 0; | 
| 749 |  |  |  |  |  |  | my $buffer = "\0" x ($len + 1); | 
| 750 |  |  |  |  |  |  | $xsub->($buffer, $len); | 
| 751 |  |  |  |  |  |  | return substr($buffer, 0, $len); | 
| 752 |  |  |  |  |  |  | } | 
| 753 |  |  |  |  |  |  | ], | 
| 754 |  |  |  |  |  |  |  | 
| 755 |  |  |  |  |  |  | # void | 
| 756 |  |  |  |  |  |  | # sodium_add(unsigned char *a, const unsigned char *b, const size_t len) | 
| 757 |  |  |  |  |  |  | 'sodium_add' => [ | 
| 758 |  |  |  |  |  |  | ['string', 'string', 'size_t'] => 'void', | 
| 759 |  |  |  |  |  |  | sub { | 
| 760 |  |  |  |  |  |  | my ($xsub, $bin_string1, $bin_string2, $len) = @_; | 
| 761 |  |  |  |  |  |  | return unless $bin_string1 && $bin_string2; | 
| 762 |  |  |  |  |  |  | $len //= length($bin_string1); | 
| 763 |  |  |  |  |  |  | my $copy = substr($bin_string1, 0); | 
| 764 |  |  |  |  |  |  | $xsub->($copy, $bin_string2, $len); | 
| 765 |  |  |  |  |  |  | return $copy; | 
| 766 |  |  |  |  |  |  | } | 
| 767 |  |  |  |  |  |  | ], | 
| 768 |  |  |  |  |  |  |  | 
| 769 |  |  |  |  |  |  | # int | 
| 770 |  |  |  |  |  |  | # sodium_base642bin( | 
| 771 |  |  |  |  |  |  | #   unsigned char * const bin, const size_t bin_maxlen, | 
| 772 |  |  |  |  |  |  | #   const char * const b64, const size_t b64_len, | 
| 773 |  |  |  |  |  |  | #   const char * const ignore, size_t * const bin_len, | 
| 774 |  |  |  |  |  |  | #   const char ** const b64_end, const int variant); | 
| 775 |  |  |  |  |  |  | 'sodium_base642bin' => [ | 
| 776 |  |  |  |  |  |  | ['string', 'size_t', 'string', 'size_t', 'string', 'size_t*', 'string*', 'int'] => 'int', | 
| 777 |  |  |  |  |  |  | sub { | 
| 778 |  |  |  |  |  |  | my ($xsub, $b64, $variant) = @_; | 
| 779 |  |  |  |  |  |  | my $b64_len = length($b64); | 
| 780 |  |  |  |  |  |  | $variant //= Sodium::FFI::sodium_base64_VARIANT_ORIGINAL; | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | my $bin_max_len = $b64_len / 4 * 3 + 2; | 
| 783 |  |  |  |  |  |  | my $bin = "\0" x $bin_max_len; | 
| 784 |  |  |  |  |  |  | my $bin_real_len = 0; | 
| 785 |  |  |  |  |  |  |  | 
| 786 |  |  |  |  |  |  | my $ignore = undef; | 
| 787 |  |  |  |  |  |  | my $end = undef; | 
| 788 |  |  |  |  |  |  | $xsub->($bin, $bin_max_len, $b64, $b64_len, $ignore, \$bin_real_len, \$end, $variant); | 
| 789 |  |  |  |  |  |  | # $bin =~ s/\0//g; | 
| 790 |  |  |  |  |  |  | return substr($bin, 0, $bin_real_len); | 
| 791 |  |  |  |  |  |  | } | 
| 792 |  |  |  |  |  |  | ], | 
| 793 |  |  |  |  |  |  |  | 
| 794 |  |  |  |  |  |  | # char * | 
| 795 |  |  |  |  |  |  | # sodium_bin2base64(char * const b64, const size_t b64_maxlen, | 
| 796 |  |  |  |  |  |  | #   const unsigned char * const bin, const size_t bin_len, | 
| 797 |  |  |  |  |  |  | #   const int variant); | 
| 798 |  |  |  |  |  |  | 'sodium_bin2base64' => [ | 
| 799 |  |  |  |  |  |  | ['string', 'size_t', 'string', 'size_t', 'int'] => 'string', | 
| 800 |  |  |  |  |  |  | sub { | 
| 801 |  |  |  |  |  |  | my ($xsub, $bin, $variant) = @_; | 
| 802 |  |  |  |  |  |  | my $bin_len = length($bin); | 
| 803 |  |  |  |  |  |  | $variant //= Sodium::FFI::sodium_base64_VARIANT_ORIGINAL; | 
| 804 |  |  |  |  |  |  |  | 
| 805 |  |  |  |  |  |  | my $b64_len = Sodium::FFI::sodium_base64_encoded_len($bin_len, $variant); | 
| 806 |  |  |  |  |  |  | my $b64 = "\0" x $b64_len; | 
| 807 |  |  |  |  |  |  |  | 
| 808 |  |  |  |  |  |  | $xsub->($b64, $b64_len, $bin, $bin_len, $variant); | 
| 809 |  |  |  |  |  |  | $b64 =~ s/\0//g; | 
| 810 |  |  |  |  |  |  | return $b64; | 
| 811 |  |  |  |  |  |  | } | 
| 812 |  |  |  |  |  |  | ], | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | # char * | 
| 815 |  |  |  |  |  |  | # sodium_bin2hex(char *const hex, const size_t hex_maxlen, | 
| 816 |  |  |  |  |  |  | #   const unsigned char *const bin, const size_t bin_len) | 
| 817 |  |  |  |  |  |  | 'sodium_bin2hex' => [ | 
| 818 |  |  |  |  |  |  | ['string', 'size_t', 'string', 'size_t'] => 'string', | 
| 819 |  |  |  |  |  |  | sub { | 
| 820 |  |  |  |  |  |  | my ($xsub, $bin_string) = @_; | 
| 821 |  |  |  |  |  |  | return unless $bin_string; | 
| 822 |  |  |  |  |  |  | my $bin_len = length($bin_string); | 
| 823 |  |  |  |  |  |  | my $hex_max = $bin_len * 2; | 
| 824 |  |  |  |  |  |  |  | 
| 825 |  |  |  |  |  |  | my $buffer = "\0" x ($hex_max + 1); | 
| 826 |  |  |  |  |  |  | $xsub->($buffer, $hex_max + 1, $bin_string, $bin_len); | 
| 827 |  |  |  |  |  |  | return substr($buffer, 0, $hex_max); | 
| 828 |  |  |  |  |  |  | } | 
| 829 |  |  |  |  |  |  | ], | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  | # int | 
| 832 |  |  |  |  |  |  | # sodium_hex2bin( | 
| 833 |  |  |  |  |  |  | #    unsigned char *const bin, const size_t bin_maxlen, | 
| 834 |  |  |  |  |  |  | #    const char *const hex, const size_t hex_len, | 
| 835 |  |  |  |  |  |  | #    const char *const ignore, size_t *const bin_len, const char **const hex_end) | 
| 836 |  |  |  |  |  |  | 'sodium_hex2bin' => [ | 
| 837 |  |  |  |  |  |  | ['string', 'size_t', 'string', 'size_t', 'string', 'size_t *', 'string *'] => 'int', | 
| 838 |  |  |  |  |  |  | sub { | 
| 839 |  |  |  |  |  |  | my ($xsub, $hex_string, %params) = @_; | 
| 840 |  |  |  |  |  |  | $hex_string //= ''; | 
| 841 |  |  |  |  |  |  | my $hex_len = length($hex_string); | 
| 842 |  |  |  |  |  |  |  | 
| 843 |  |  |  |  |  |  | # these two are mostly always void/undef | 
| 844 |  |  |  |  |  |  | my $ignore = $params{ignore}; | 
| 845 |  |  |  |  |  |  | my $hex_end = $params{hex_end}; | 
| 846 |  |  |  |  |  |  |  | 
| 847 |  |  |  |  |  |  | my $bin_max_len = $params{max_len} // 0; | 
| 848 |  |  |  |  |  |  | if ($bin_max_len <= 0) { | 
| 849 |  |  |  |  |  |  | $bin_max_len = $hex_len; | 
| 850 |  |  |  |  |  |  | $bin_max_len = int($hex_len / 2) unless $ignore; | 
| 851 |  |  |  |  |  |  | } | 
| 852 |  |  |  |  |  |  | my $buffer = "\0" x ($hex_len + 1); | 
| 853 |  |  |  |  |  |  | my $bin_len = 0; | 
| 854 |  |  |  |  |  |  |  | 
| 855 |  |  |  |  |  |  | my $ret = $xsub->($buffer, $hex_len, $hex_string, $hex_len, $ignore, \$bin_len, \$hex_end); | 
| 856 |  |  |  |  |  |  | unless ($ret == 0) { | 
| 857 |  |  |  |  |  |  | croak("sodium_hex2bin failed with: $ret"); | 
| 858 |  |  |  |  |  |  | } | 
| 859 |  |  |  |  |  |  |  | 
| 860 |  |  |  |  |  |  | return substr($buffer, 0, $bin_max_len) if $bin_max_len < $bin_len; | 
| 861 |  |  |  |  |  |  | return substr($buffer, 0, $bin_len); | 
| 862 |  |  |  |  |  |  | } | 
| 863 |  |  |  |  |  |  | ], | 
| 864 |  |  |  |  |  |  |  | 
| 865 |  |  |  |  |  |  | # void | 
| 866 |  |  |  |  |  |  | # sodium_increment(unsigned char *n, const size_t nlen) | 
| 867 |  |  |  |  |  |  | 'sodium_increment' => [ | 
| 868 |  |  |  |  |  |  | ['string', 'size_t'] => 'void', | 
| 869 |  |  |  |  |  |  | sub { | 
| 870 |  |  |  |  |  |  | my ($xsub, $bin_string, $len) = @_; | 
| 871 |  |  |  |  |  |  | return unless $bin_string; | 
| 872 |  |  |  |  |  |  | $len //= length($bin_string); | 
| 873 |  |  |  |  |  |  | my $copy = substr($bin_string, 0); | 
| 874 |  |  |  |  |  |  | $xsub->($copy, $len); | 
| 875 |  |  |  |  |  |  | return $copy; | 
| 876 |  |  |  |  |  |  | } | 
| 877 |  |  |  |  |  |  | ], | 
| 878 |  |  |  |  |  |  |  | 
| 879 |  |  |  |  |  |  | # int | 
| 880 |  |  |  |  |  |  | # sodium_is_zero(const unsigned char *n, const size_t nlen) | 
| 881 |  |  |  |  |  |  | 'sodium_is_zero' => [ | 
| 882 |  |  |  |  |  |  | ['string', 'size_t'] => 'int', | 
| 883 |  |  |  |  |  |  | sub { | 
| 884 |  |  |  |  |  |  | my ($xsub, $bin_string, $len) = @_; | 
| 885 |  |  |  |  |  |  | $len //= length($bin_string); | 
| 886 |  |  |  |  |  |  | return $xsub->($bin_string, $len); | 
| 887 |  |  |  |  |  |  | } | 
| 888 |  |  |  |  |  |  | ], | 
| 889 |  |  |  |  |  |  |  | 
| 890 |  |  |  |  |  |  | # int | 
| 891 |  |  |  |  |  |  | # sodium_memcmp(const void * const b1_, const void * const b2_, size_t len); | 
| 892 |  |  |  |  |  |  | 'sodium_memcmp' => [ | 
| 893 |  |  |  |  |  |  | ['string', 'string', 'size_t'] => 'int', | 
| 894 |  |  |  |  |  |  | sub { | 
| 895 |  |  |  |  |  |  | my ($xsub, $string_x, $string_y, $len) = @_; | 
| 896 |  |  |  |  |  |  | return unless $string_x; | 
| 897 |  |  |  |  |  |  | $len //= length($string_x); | 
| 898 |  |  |  |  |  |  | return $xsub->($string_x, $string_y, $len); | 
| 899 |  |  |  |  |  |  | } | 
| 900 |  |  |  |  |  |  | ], | 
| 901 |  |  |  |  |  |  |  | 
| 902 |  |  |  |  |  |  | ); | 
| 903 |  |  |  |  |  |  |  | 
| 904 |  |  |  |  |  |  | our %maybe_function = ( | 
| 905 |  |  |  |  |  |  | # void | 
| 906 |  |  |  |  |  |  | # randombytes_buf_deterministic(void * const buf, const size_t size, | 
| 907 |  |  |  |  |  |  | #   const unsigned char seed[randombytes_SEEDBYTES]); | 
| 908 |  |  |  |  |  |  | 'randombytes_buf_deterministic' => { | 
| 909 |  |  |  |  |  |  | added => [1,0,12], | 
| 910 |  |  |  |  |  |  | ffi => [ | 
| 911 |  |  |  |  |  |  | ['string', 'size_t', 'string'] => 'void', | 
| 912 |  |  |  |  |  |  | sub { | 
| 913 |  |  |  |  |  |  | my ($xsub, $len, $seed) = @_; | 
| 914 |  |  |  |  |  |  | $len //= 0; | 
| 915 |  |  |  |  |  |  | return '' unless $len > 0; | 
| 916 |  |  |  |  |  |  | my $buffer = "\0" x ($len + 1); | 
| 917 |  |  |  |  |  |  | $xsub->($buffer, $len, $seed); | 
| 918 |  |  |  |  |  |  | return substr($buffer, 0, $len); | 
| 919 |  |  |  |  |  |  | } | 
| 920 |  |  |  |  |  |  | ], | 
| 921 |  |  |  |  |  |  | fallback => sub { croak("randombytes_buf_deterministic not implemented until libsodium v1.0.12"); }, | 
| 922 |  |  |  |  |  |  | }, | 
| 923 |  |  |  |  |  |  |  | 
| 924 |  |  |  |  |  |  |  | 
| 925 |  |  |  |  |  |  | # int | 
| 926 |  |  |  |  |  |  | # sodium_compare(const unsigned char *b1_, | 
| 927 |  |  |  |  |  |  | #   const unsigned char *b2_, size_t len) | 
| 928 |  |  |  |  |  |  | 'sodium_compare' => { | 
| 929 |  |  |  |  |  |  | added => [1,0,4], | 
| 930 |  |  |  |  |  |  | ffi => [ | 
| 931 |  |  |  |  |  |  | ['string', 'string', 'size_t'] => 'int', | 
| 932 |  |  |  |  |  |  | sub { | 
| 933 |  |  |  |  |  |  | my ($xsub, $bin_string1, $bin_string2, $len) = @_; | 
| 934 |  |  |  |  |  |  | return unless $bin_string1 && $bin_string2; | 
| 935 |  |  |  |  |  |  | $len //= length($bin_string1); | 
| 936 |  |  |  |  |  |  | my $int = $xsub->($bin_string1, $bin_string2, $len); | 
| 937 |  |  |  |  |  |  | return $int; | 
| 938 |  |  |  |  |  |  | } | 
| 939 |  |  |  |  |  |  | ], | 
| 940 |  |  |  |  |  |  | fallback => sub { croak("sodium_compare not implemented until libsodium v1.0.4"); }, | 
| 941 |  |  |  |  |  |  | }, | 
| 942 |  |  |  |  |  |  |  | 
| 943 |  |  |  |  |  |  | # int | 
| 944 |  |  |  |  |  |  | # sodium_library_minimal(void) | 
| 945 |  |  |  |  |  |  | 'sodium_library_minimal' => { | 
| 946 |  |  |  |  |  |  | added => [1,0,12], | 
| 947 |  |  |  |  |  |  | ffi => [[], 'int'], | 
| 948 |  |  |  |  |  |  | fallback => sub { croak("sodium_library_minimal not implemented until libsodium v1.0.12"); }, | 
| 949 |  |  |  |  |  |  | }, | 
| 950 |  |  |  |  |  |  |  | 
| 951 |  |  |  |  |  |  | # int | 
| 952 |  |  |  |  |  |  | # sodium_pad(size_t *padded_buflen_p, unsigned char *buf, | 
| 953 |  |  |  |  |  |  | # size_t unpadded_buflen, size_t blocksize, size_t max_buflen) | 
| 954 |  |  |  |  |  |  | 'sodium_pad' => { | 
| 955 |  |  |  |  |  |  | added => [1,0,14], | 
| 956 |  |  |  |  |  |  | ffi => [ | 
| 957 |  |  |  |  |  |  | ['size_t', 'string', 'size_t', 'size_t', 'size_t'] => 'int', | 
| 958 |  |  |  |  |  |  | sub { | 
| 959 |  |  |  |  |  |  | my ($xsub, $unpadded, $block_size) = @_; | 
| 960 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 961 |  |  |  |  |  |  | my $unpadded_len = length($unpadded); | 
| 962 |  |  |  |  |  |  | $block_size //= 16; | 
| 963 |  |  |  |  |  |  | $block_size = 16 if $block_size < 0; | 
| 964 |  |  |  |  |  |  |  | 
| 965 |  |  |  |  |  |  | my $xpadlen = $block_size - 1; | 
| 966 |  |  |  |  |  |  | if (($block_size & ($block_size - 1)) == 0) { | 
| 967 |  |  |  |  |  |  | $xpadlen -= $unpadded_len & ($block_size - 1); | 
| 968 |  |  |  |  |  |  | } else { | 
| 969 |  |  |  |  |  |  | $xpadlen -= $unpadded_len % $block_size; | 
| 970 |  |  |  |  |  |  | } | 
| 971 |  |  |  |  |  |  | if ($SIZE_MAX - $unpadded_len <= $xpadlen) { | 
| 972 |  |  |  |  |  |  | croak("Input is too large."); | 
| 973 |  |  |  |  |  |  | } | 
| 974 |  |  |  |  |  |  |  | 
| 975 |  |  |  |  |  |  | my $xpadded_len = $unpadded_len + $xpadlen; | 
| 976 |  |  |  |  |  |  | my $padded = "\0" x ($xpadded_len + 1); | 
| 977 |  |  |  |  |  |  | if ($unpadded_len > 0) { | 
| 978 |  |  |  |  |  |  | my $st = 1; | 
| 979 |  |  |  |  |  |  | my $i = 0; | 
| 980 |  |  |  |  |  |  | my $k = $unpadded_len; | 
| 981 |  |  |  |  |  |  | for my $j (0..$xpadded_len) { | 
| 982 |  |  |  |  |  |  | substr($padded, $j, 1) = substr($unpadded, $i, 1); | 
| 983 |  |  |  |  |  |  | $k -= $st; | 
| 984 |  |  |  |  |  |  | $st = (~((((($k >> 48) | ($k >> 32) | ($k >> 16) | $k) & 0xffff) - 1) >> 16)) & 1; | 
| 985 |  |  |  |  |  |  | $i += $st; | 
| 986 |  |  |  |  |  |  | } | 
| 987 |  |  |  |  |  |  | } | 
| 988 |  |  |  |  |  |  | my $int = $xsub->(undef, $padded, $unpadded_len, $block_size, $xpadded_len + 1); | 
| 989 |  |  |  |  |  |  | return $padded; | 
| 990 |  |  |  |  |  |  | } | 
| 991 |  |  |  |  |  |  | ], | 
| 992 |  |  |  |  |  |  | fallback => sub { croak("sodium_pad not implemented until libsodium v1.0.14"); }, | 
| 993 |  |  |  |  |  |  | }, | 
| 994 |  |  |  |  |  |  |  | 
| 995 |  |  |  |  |  |  | # void | 
| 996 |  |  |  |  |  |  | # sodium_sub(unsigned char *a, const unsigned char *b, const size_t len); | 
| 997 |  |  |  |  |  |  | 'sodium_sub' => { | 
| 998 |  |  |  |  |  |  | added => [1,0,17], | 
| 999 |  |  |  |  |  |  | ffi => [ | 
| 1000 |  |  |  |  |  |  | ['string', 'string', 'size_t'] => 'void', | 
| 1001 |  |  |  |  |  |  | sub { | 
| 1002 |  |  |  |  |  |  | my ($xsub, $bin_string1, $bin_string2, $len) = @_; | 
| 1003 |  |  |  |  |  |  | return unless $bin_string1 && $bin_string2; | 
| 1004 |  |  |  |  |  |  | $len //= length($bin_string1); | 
| 1005 |  |  |  |  |  |  | my $copy = substr($bin_string1, 0); | 
| 1006 |  |  |  |  |  |  | $xsub->($copy, $bin_string2, $len); | 
| 1007 |  |  |  |  |  |  | return $copy; | 
| 1008 |  |  |  |  |  |  | } | 
| 1009 |  |  |  |  |  |  | ], | 
| 1010 |  |  |  |  |  |  | fallback => sub { croak("sodium_sub not implemented until libsodium v1.0.17"); }, | 
| 1011 |  |  |  |  |  |  | }, | 
| 1012 |  |  |  |  |  |  |  | 
| 1013 |  |  |  |  |  |  | # int | 
| 1014 |  |  |  |  |  |  | # sodium_unpad(size_t *unpadded_buflen_p, const unsigned char *buf, | 
| 1015 |  |  |  |  |  |  | # size_t padded_buflen, size_t blocksize) | 
| 1016 |  |  |  |  |  |  | 'sodium_unpad' => { | 
| 1017 |  |  |  |  |  |  | added => [1,0,14], | 
| 1018 |  |  |  |  |  |  | ffi => [ | 
| 1019 |  |  |  |  |  |  | ['size_t*', 'string', 'size_t', 'size_t'] => 'int', | 
| 1020 |  |  |  |  |  |  | sub { | 
| 1021 |  |  |  |  |  |  | my ($xsub, $padded, $block_size) = @_; | 
| 1022 |  |  |  |  |  |  | $block_size //= 16; | 
| 1023 |  |  |  |  |  |  | $block_size = 16 if $block_size < 0; | 
| 1024 |  |  |  |  |  |  |  | 
| 1025 |  |  |  |  |  |  | my $SIZE_MAX = Sodium::FFI::SIZE_MAX; | 
| 1026 |  |  |  |  |  |  | my $padded_len = length($padded); | 
| 1027 |  |  |  |  |  |  | if ($padded_len < $block_size) { | 
| 1028 |  |  |  |  |  |  | croak("Invalid padding."); | 
| 1029 |  |  |  |  |  |  | } | 
| 1030 |  |  |  |  |  |  | my $unpadded_len = 0; | 
| 1031 |  |  |  |  |  |  | my $int = $xsub->(\$unpadded_len, $padded, $padded_len, $block_size); | 
| 1032 |  |  |  |  |  |  | return substr($padded, 0, $unpadded_len); | 
| 1033 |  |  |  |  |  |  | } | 
| 1034 |  |  |  |  |  |  | ], | 
| 1035 |  |  |  |  |  |  | fallback => sub { croak("sodium_unpad not implemented until libsodium v1.0.14"); }, | 
| 1036 |  |  |  |  |  |  | }, | 
| 1037 |  |  |  |  |  |  | ); | 
| 1038 |  |  |  |  |  |  |  | 
| 1039 |  |  |  |  |  |  | foreach my $func (keys %function) { | 
| 1040 |  |  |  |  |  |  | $ffi->attach($func, @{$function{$func}}); | 
| 1041 |  |  |  |  |  |  | push(@EXPORT_OK, $func) unless ref($func); | 
| 1042 |  |  |  |  |  |  | } | 
| 1043 |  |  |  |  |  |  |  | 
| 1044 |  |  |  |  |  |  | foreach my $func (keys %maybe_function) { | 
| 1045 |  |  |  |  |  |  | my $href = $maybe_function{$func}; | 
| 1046 |  |  |  |  |  |  | if (_version_or_better(@{$href->{added}})) { | 
| 1047 |  |  |  |  |  |  | $ffi->attach($func, @{$href->{ffi}}); | 
| 1048 |  |  |  |  |  |  | } | 
| 1049 |  |  |  |  |  |  | else { | 
| 1050 |  |  |  |  |  |  | # monkey patch in the subref | 
| 1051 | 9 |  |  | 9 |  | 153526 | no strict 'refs'; | 
|  | 9 |  |  |  |  | 28 |  | 
|  | 9 |  |  |  |  | 316 |  | 
| 1052 | 9 |  |  | 9 |  | 68 | no warnings 'redefine'; | 
|  | 9 |  |  |  |  | 34 |  | 
|  | 9 |  |  |  |  | 3471 |  | 
| 1053 |  |  |  |  |  |  | my $pkg = __PACKAGE__; | 
| 1054 |  |  |  |  |  |  | *{"${pkg}::$func"} = set_subname("${pkg}::$func", $href->{fallback}); | 
| 1055 |  |  |  |  |  |  | } | 
| 1056 |  |  |  |  |  |  | push @EXPORT_OK, $func; | 
| 1057 |  |  |  |  |  |  | } | 
| 1058 |  |  |  |  |  |  |  | 
| 1059 |  |  |  |  |  |  | sub _version_or_better { | 
| 1060 | 59 |  |  | 59 |  | 2641 | my ($maj, $min, $pat) = @_; | 
| 1061 | 59 |  | 50 |  |  | 174 | $maj //= 0; | 
| 1062 | 59 |  | 50 |  |  | 126 | $min //= 0; | 
| 1063 | 59 |  | 50 |  |  | 104 | $pat //= 0; | 
| 1064 | 59 |  |  |  |  | 119 | foreach my $partial ($maj, $min, $pat) { | 
| 1065 | 177 | 50 |  |  |  | 514 | if ($partial =~ /[^0-9]/) { | 
| 1066 | 0 |  |  |  |  | 0 | croak("_version_or_better requires 1 - 3 integers representing major, minor and patch numbers"); | 
| 1067 |  |  |  |  |  |  | } | 
| 1068 |  |  |  |  |  |  | } | 
| 1069 |  |  |  |  |  |  | # if no number was passed in, then the current version is higher | 
| 1070 | 59 | 0 | 33 |  |  | 146 | return 1 unless ($maj || $min || $pat); | 
|  |  |  | 33 |  |  |  |  | 
| 1071 |  |  |  |  |  |  |  | 
| 1072 | 59 |  |  |  |  | 414 | my $version_string = Sodium::FFI::sodium_version_string(); | 
| 1073 | 59 | 50 |  |  |  | 139 | croak("No version string") unless $version_string; | 
| 1074 | 59 |  |  |  |  | 196 | my ($smaj, $smin, $spatch) = split(/\./, $version_string); | 
| 1075 | 59 | 50 |  |  |  | 170 | return 0 if $smaj < $maj; # full version behind of requested | 
| 1076 | 59 | 50 |  |  |  | 142 | return 1 if $smaj > $maj; # full version ahead of requested | 
| 1077 |  |  |  |  |  |  | # now we should be matching major versions | 
| 1078 | 59 | 50 |  |  |  | 224 | return 1 unless $min; # if we were only given major, move on | 
| 1079 | 0 | 0 |  |  |  |  | return 0 if $smin < $min; # same major, lower minor | 
| 1080 | 0 | 0 |  |  |  |  | return 1 if $smaj > $min; # same major, higher minor | 
| 1081 |  |  |  |  |  |  | # now we should be matching major and minor, check patch | 
| 1082 | 0 | 0 |  |  |  |  | return 1 unless $pat; # move on if we were given maj, min only | 
| 1083 | 0 | 0 |  |  |  |  | return 0 if $spatch < $pat; | 
| 1084 | 0 |  |  |  |  |  | return 1; | 
| 1085 |  |  |  |  |  |  | } | 
| 1086 |  |  |  |  |  |  |  | 
| 1087 |  |  |  |  |  |  | 1; | 
| 1088 |  |  |  |  |  |  |  | 
| 1089 |  |  |  |  |  |  | __END__ |