Skip to content

Commit c1a18fd

Browse files
committed
Add a few more utils functions
1 parent 9c0499b commit c1a18fd

File tree

4 files changed

+172
-17
lines changed

4 files changed

+172
-17
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ xx*
2727
lib/*.c
2828
lib/UV/*.c
2929
.tmp/
30+
fbx.json
31+
foo.pl
32+
*.phpt

ffi/ffi.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
#include <stdint.h>
44
#include <sodium.h>
55

6+
#if !defined(SODIUM_LIBRARY_MINIMAL)
7+
#define SODIUM_LIBRARY_MINIMAL 0
8+
#endif
69
#define _str(name) c->set_str(#name, name)
710
#define _sint(name) c->set_sint(#name, name)
11+
#define _uint(name) c->set_uint(#name, name)
812

913
void
1014
ffi_pl_bundle_constant(const char* package, ffi_platypus_constant_t* c)
1115
{
1216
_str(SODIUM_VERSION_STRING);
13-
17+
_uint(SIZE_MAX);
18+
_sint(SODIUM_LIBRARY_MINIMAL);
1419
_sint(SODIUM_LIBRARY_VERSION_MAJOR);
1520
_sint(SODIUM_LIBRARY_VERSION_MINOR);
1621
}

lib/Sodium/FFI.pm

+117-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,21 @@ $ffi->attach('sodium_library_version_major' => [] => 'int');
2727
$ffi->attach('sodium_library_version_minor' => [] => 'int');
2828

2929
our %function = (
30+
# void
31+
# sodium_add(unsigned char *a, const unsigned char *b, const size_t len)
32+
'sodium_add' => [
33+
['string', 'string', 'size_t'] => 'void',
34+
sub {
35+
my ($xsub, $bin_string1, $bin_string2, $len) = @_;
36+
return unless $bin_string1 && $bin_string2;
37+
$len //= length($bin_string1);
38+
$xsub->($bin_string1, $bin_string2, $len);
39+
}
40+
],
41+
3042
# char *
3143
# sodium_bin2hex(char *const hex, const size_t hex_maxlen,
32-
# const unsigned char *const bin, const size_t bin_len)
44+
# const unsigned char *const bin, const size_t bin_len)
3345
'sodium_bin2hex' => [
3446
['string', 'size_t', 'string', 'size_t'] => 'string',
3547
sub {
@@ -44,7 +56,8 @@ our %function = (
4456
}
4557
],
4658

47-
# int sodium_hex2bin(
59+
# int
60+
# sodium_hex2bin(
4861
# unsigned char *const bin, const size_t bin_maxlen,
4962
# const char *const hex, const size_t hex_len,
5063
# const char *const ignore, size_t *const bin_len, const char **const hex_end)
@@ -76,15 +89,116 @@ our %function = (
7689
return substr($buffer, 0, $bin_len);
7790
}
7891
],
92+
93+
# void
94+
# sodium_increment(unsigned char *n, const size_t nlen)
95+
'sodium_increment' => [
96+
['string', 'size_t'] => 'void',
97+
sub {
98+
my ($xsub, $bin_string, $len) = @_;
99+
return unless $bin_string;
100+
$len //= length($bin_string);
101+
$xsub->($bin_string, $len);
102+
}
103+
],
104+
79105
);
80106

81107
our %maybe_function = (
108+
# int
109+
# sodium_compare(const unsigned char *b1_,
110+
# const unsigned char *b2_, size_t len)
111+
'sodium_compare' => {
112+
added => [1,0,4],
113+
ffi => [
114+
['string', 'string', 'size_t'] => 'int',
115+
sub {
116+
my ($xsub, $bin_string1, $bin_string2, $len) = @_;
117+
return unless $bin_string1 && $bin_string2;
118+
$len //= length($bin_string1);
119+
my $int = $xsub->($bin_string1, $bin_string2, $len);
120+
return $int;
121+
}
122+
],
123+
fallback => sub { croak("sodium_compare not implemented until libsodium v1.0.4"); },
124+
},
125+
126+
# int
127+
# sodium_library_minimal(void)
82128
'sodium_library_minimal' => {
83129
added => [1,0,12],
84-
# uint64_t uv_get_constrained_memory(void)
85130
ffi => [[], 'int'],
86131
fallback => sub { croak("sodium_library_minimal not implemented until libsodium v1.0.12"); },
87132
},
133+
134+
# int
135+
# sodium_pad(size_t *padded_buflen_p, unsigned char *buf,
136+
# size_t unpadded_buflen, size_t blocksize, size_t max_buflen)
137+
'sodium_pad' => {
138+
added => [1,0,14],
139+
ffi => [
140+
['size_t', 'string', 'size_t', 'size_t', 'size_t'] => 'int',
141+
sub {
142+
my ($xsub, $unpadded, $block_size) = @_;
143+
my $SIZE_MAX = Sodium::FFI::SIZE_MAX;
144+
my $unpadded_len = length($unpadded);
145+
$block_size //= 16;
146+
$block_size = 16 if $block_size < 0;
147+
148+
my $xpadlen = $block_size - 1;
149+
if (($block_size & ($block_size - 1)) == 0) {
150+
$xpadlen -= $unpadded_len & ($block_size - 1);
151+
} else {
152+
$xpadlen -= $unpadded_len % $block_size;
153+
}
154+
if ($SIZE_MAX - $unpadded_len <= $xpadlen) {
155+
croak("Input is too large.");
156+
}
157+
158+
my $xpadded_len = $unpadded_len + $xpadlen;
159+
my $padded = "\0" x ($xpadded_len + 1);
160+
if ($unpadded_len > 0) {
161+
my $st = 1;
162+
my $i = 0;
163+
my $k = $unpadded_len;
164+
for my $j (0..$xpadded_len) {
165+
substr($padded, $j, 1) = substr($unpadded, $i, 1);
166+
$k -= $st;
167+
$st = (~((((($k >> 48) | ($k >> 32) | ($k >> 16) | $k) & 0xffff) - 1) >> 16)) & 1;
168+
$i += $st;
169+
}
170+
}
171+
my $int = $xsub->(undef, $padded, $unpadded_len, $block_size, $xpadded_len + 1);
172+
return $padded;
173+
}
174+
],
175+
fallback => sub { croak("sodium_pad not implemented until libsodium v1.0.14"); },
176+
},
177+
178+
# int
179+
# sodium_unpad(size_t *unpadded_buflen_p, const unsigned char *buf,
180+
# size_t padded_buflen, size_t blocksize)
181+
'sodium_unpad' => {
182+
added => [1,0,14],
183+
ffi => [
184+
['size_t*', 'string', 'size_t', 'size_t'] => 'int',
185+
sub {
186+
my ($xsub, $padded, $block_size) = @_;
187+
$block_size //= 16;
188+
$block_size = 16 if $block_size < 0;
189+
190+
my $SIZE_MAX = Sodium::FFI::SIZE_MAX;
191+
my $padded_len = length($padded);
192+
if ($padded_len < $block_size) {
193+
croak("Invalid padding.");
194+
}
195+
my $unpadded_len = 0;
196+
my $int = $xsub->(\$unpadded_len, $padded, $padded_len, $block_size);
197+
return substr($padded, 0, $unpadded_len);
198+
}
199+
],
200+
fallback => sub { croak("sodium_unpad not implemented until libsodium v1.0.14"); },
201+
},
88202
);
89203

90204
foreach my $func (keys %function) {

t/11-utils.t

+46-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
use strict;
22
use warnings;
33
use Test::More;
4-
use Sodium::FFI qw(sodium_bin2hex sodium_hex2bin);
4+
use Sodium::FFI qw(
5+
sodium_add sodium_bin2hex sodium_compare sodium_hex2bin sodium_increment
6+
sodium_library_minimal sodium_pad sodium_unpad
7+
);
8+
9+
# diag("SIZE_MAX is: " . Sodium::FFI::SIZE_MAX);
510

611
# hex2bin
712
is(sodium_hex2bin("414243", ignore => ': '), "ABC", "hex2bin: ignore ': ': 414243 = ABC");
@@ -22,18 +27,46 @@ is($readable, 'cafe6942', "hex2bin: maxlen 4, ignore ': ': readable; Cafe : 6942
2227
{
2328
my $hex = '414243';
2429
my $bin = sodium_hex2bin($hex);
25-
is($bin, 'ABC', 'round-trip: first leg ok');
26-
my $new_hex;
27-
my $error;
28-
{
29-
local $@;
30-
$error = $@ || 'Error' unless eval {
31-
$new_hex = sodium_bin2hex($bin);
32-
1;
33-
};
34-
}
35-
is($new_hex, $hex, 'round-trip: second leg ok. YAY');
36-
ok(!$error, 'no errors on the round trip');
30+
is($bin, 'ABC', 'hex2bin: first leg ok');
31+
my $new_hex = sodium_bin2hex($bin);
32+
is($new_hex, $hex, 'bin2hex: second leg ok. YAY');
33+
}
34+
35+
# sodium_add, sodium_increment
36+
{
37+
my $left = "\xFF\xFF\x80\x01\x02\x03\x04\x05\x06\x07\x08";
38+
sodium_increment($left);
39+
is(sodium_bin2hex($left), '0000810102030405060708', 'increment, bin2hex: Got the right answer');
40+
my $right = "\x01\x02\x03\x04\x05\x06\x07\x08\xFA\xFB\xFC";
41+
sodium_add($left, $right);
42+
is(sodium_bin2hex($left), '0102840507090b0d000305', 'add, bin2hex: Got the right answer');
3743
}
3844

45+
# sodium_compare
46+
SKIP: {
47+
skip('sodium_compare implemented in libsodium >= v1.0.4', 3) unless Sodium::FFI::_version_or_better(1, 0, 4);
48+
my $v1 = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
49+
my $v2 = "\x02\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
50+
is(sodium_compare($v1, $v2), -1, 'sodium_compare: v1 < v2');
51+
sodium_increment($v1);
52+
is(sodium_compare($v1, $v2), 0, 'sodium_compare: increment sets v1 == v2');
53+
sodium_increment($v1);
54+
is(sodium_compare($v1, $v2), 1, 'sodium_compare: increment sets v1 > v2');
55+
};
56+
57+
# sodium_pad
58+
SKIP: {
59+
skip('sodium_pad implemented in libsodium >= v1.0.14', 2) unless Sodium::FFI::_version_or_better(1, 0, 14);
60+
my $str = 'xyz';
61+
my $str_padded = sodium_pad($str, 16);
62+
is(sodium_bin2hex($str_padded), '78797a80000000000000000000000000', 'sodium_pad: looks right');
63+
is(sodium_unpad($str_padded, 16), $str, 'sodium_unpad: round trip is good');
64+
};
65+
66+
# sodium_library_minimal
67+
SKIP: {
68+
skip('sodium_library_minimal implemented in libsodium >= v1.0.12', 1) unless Sodium::FFI::_version_or_better(1, 0, 12);
69+
is(sodium_library_minimal, Sodium::FFI::SODIUM_LIBRARY_MINIMAL, 'sodium_library_minimal: Got the right answer');
70+
};
71+
3972
done_testing;

0 commit comments

Comments
 (0)