xcrypt 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +106 -0
  3. data/ext/libxcrypt/AUTHORS +38 -0
  4. data/ext/libxcrypt/COPYING.LIB +502 -0
  5. data/ext/libxcrypt/ChangeLog +239 -0
  6. data/ext/libxcrypt/INSTALL +380 -0
  7. data/ext/libxcrypt/LICENSING +152 -0
  8. data/ext/libxcrypt/Makefile.am +704 -0
  9. data/ext/libxcrypt/Makefile.in +4110 -0
  10. data/ext/libxcrypt/NEWS +630 -0
  11. data/ext/libxcrypt/README +1 -0
  12. data/ext/libxcrypt/README.md +179 -0
  13. data/ext/libxcrypt/THANKS +13 -0
  14. data/ext/libxcrypt/TODO +1 -0
  15. data/ext/libxcrypt/TODO.md +100 -0
  16. data/ext/libxcrypt/aclocal.m4 +2617 -0
  17. data/ext/libxcrypt/autogen.sh +33 -0
  18. data/ext/libxcrypt/autom4te.cache/output.0 +19884 -0
  19. data/ext/libxcrypt/autom4te.cache/output.1 +19884 -0
  20. data/ext/libxcrypt/autom4te.cache/output.2 +19884 -0
  21. data/ext/libxcrypt/autom4te.cache/output.3 +19885 -0
  22. data/ext/libxcrypt/autom4te.cache/requests +714 -0
  23. data/ext/libxcrypt/autom4te.cache/traces.0 +4088 -0
  24. data/ext/libxcrypt/autom4te.cache/traces.1 +1060 -0
  25. data/ext/libxcrypt/autom4te.cache/traces.2 +4088 -0
  26. data/ext/libxcrypt/autom4te.cache/traces.3 +1060 -0
  27. data/ext/libxcrypt/build-aux/ci/ci-log-dependency-versions +79 -0
  28. data/ext/libxcrypt/build-aux/ci/ci-log-logfiles +22 -0
  29. data/ext/libxcrypt/build-aux/ci/clang-gcov-wrapper +2 -0
  30. data/ext/libxcrypt/build-aux/ci/configure-wrapper +10 -0
  31. data/ext/libxcrypt/build-aux/ci/summarize-coverage +24 -0
  32. data/ext/libxcrypt/build-aux/m4/ax_append_compile_flags.m4 +46 -0
  33. data/ext/libxcrypt/build-aux/m4/ax_append_flag.m4 +50 -0
  34. data/ext/libxcrypt/build-aux/m4/ax_check_compile_flag.m4 +53 -0
  35. data/ext/libxcrypt/build-aux/m4/ax_check_vscript.m4 +142 -0
  36. data/ext/libxcrypt/build-aux/m4/ax_gcc_func_attribute.m4 +246 -0
  37. data/ext/libxcrypt/build-aux/m4/ax_require_defined.m4 +37 -0
  38. data/ext/libxcrypt/build-aux/m4/ax_valgrind_check.m4 +239 -0
  39. data/ext/libxcrypt/build-aux/m4/libtool.m4 +8488 -0
  40. data/ext/libxcrypt/build-aux/m4/ltoptions.m4 +467 -0
  41. data/ext/libxcrypt/build-aux/m4/ltsugar.m4 +124 -0
  42. data/ext/libxcrypt/build-aux/m4/ltversion.m4 +24 -0
  43. data/ext/libxcrypt/build-aux/m4/lt~obsolete.m4 +99 -0
  44. data/ext/libxcrypt/build-aux/m4/pkg_compat.m4 +88 -0
  45. data/ext/libxcrypt/build-aux/m4/zw_alignment.m4 +90 -0
  46. data/ext/libxcrypt/build-aux/m4/zw_automodern.m4 +307 -0
  47. data/ext/libxcrypt/build-aux/m4/zw_detect_asan.m4 +24 -0
  48. data/ext/libxcrypt/build-aux/m4/zw_endianness.m4 +152 -0
  49. data/ext/libxcrypt/build-aux/m4/zw_ld_wrap.m4 +47 -0
  50. data/ext/libxcrypt/build-aux/m4/zw_prog_perl.m4 +40 -0
  51. data/ext/libxcrypt/build-aux/m4/zw_simple_warnings.m4 +150 -0
  52. data/ext/libxcrypt/build-aux/m4/zw_static_assert.m4 +68 -0
  53. data/ext/libxcrypt/build-aux/m4-autogen/compile +364 -0
  54. data/ext/libxcrypt/build-aux/m4-autogen/config.guess +1815 -0
  55. data/ext/libxcrypt/build-aux/m4-autogen/config.sub +2354 -0
  56. data/ext/libxcrypt/build-aux/m4-autogen/depcomp +792 -0
  57. data/ext/libxcrypt/build-aux/m4-autogen/install-sh +541 -0
  58. data/ext/libxcrypt/build-aux/m4-autogen/ltmain.sh +11524 -0
  59. data/ext/libxcrypt/build-aux/m4-autogen/missing +236 -0
  60. data/ext/libxcrypt/build-aux/m4-autogen/test-driver +160 -0
  61. data/ext/libxcrypt/build-aux/scripts/BuildCommon.pm +712 -0
  62. data/ext/libxcrypt/build-aux/scripts/check-perlcritic-config +76 -0
  63. data/ext/libxcrypt/build-aux/scripts/compute-symver-floor +116 -0
  64. data/ext/libxcrypt/build-aux/scripts/expand-selected-hashes +80 -0
  65. data/ext/libxcrypt/build-aux/scripts/gen-crypt-h +131 -0
  66. data/ext/libxcrypt/build-aux/scripts/gen-crypt-hashes-h +141 -0
  67. data/ext/libxcrypt/build-aux/scripts/gen-crypt-symbol-vers-h +150 -0
  68. data/ext/libxcrypt/build-aux/scripts/gen-libcrypt-map +67 -0
  69. data/ext/libxcrypt/build-aux/scripts/move-if-change +84 -0
  70. data/ext/libxcrypt/build-aux/scripts/skip-if-exec-format-error +78 -0
  71. data/ext/libxcrypt/codecov.yml +4 -0
  72. data/ext/libxcrypt/config.h.in +303 -0
  73. data/ext/libxcrypt/configure +19885 -0
  74. data/ext/libxcrypt/configure.ac +549 -0
  75. data/ext/libxcrypt/doc/crypt.3 +512 -0
  76. data/ext/libxcrypt/doc/crypt.5 +343 -0
  77. data/ext/libxcrypt/doc/crypt_checksalt.3 +106 -0
  78. data/ext/libxcrypt/doc/crypt_gensalt.3 +285 -0
  79. data/ext/libxcrypt/doc/crypt_gensalt_ra.3 +1 -0
  80. data/ext/libxcrypt/doc/crypt_gensalt_rn.3 +1 -0
  81. data/ext/libxcrypt/doc/crypt_preferred_method.3 +68 -0
  82. data/ext/libxcrypt/doc/crypt_r.3 +1 -0
  83. data/ext/libxcrypt/doc/crypt_ra.3 +1 -0
  84. data/ext/libxcrypt/doc/crypt_rn.3 +1 -0
  85. data/ext/libxcrypt/lib/alg-des-tables.c +3858 -0
  86. data/ext/libxcrypt/lib/alg-des.c +269 -0
  87. data/ext/libxcrypt/lib/alg-des.h +74 -0
  88. data/ext/libxcrypt/lib/alg-gost3411-2012-const.h +313 -0
  89. data/ext/libxcrypt/lib/alg-gost3411-2012-core.c +238 -0
  90. data/ext/libxcrypt/lib/alg-gost3411-2012-core.h +51 -0
  91. data/ext/libxcrypt/lib/alg-gost3411-2012-hmac.c +78 -0
  92. data/ext/libxcrypt/lib/alg-gost3411-2012-hmac.h +46 -0
  93. data/ext/libxcrypt/lib/alg-gost3411-2012-precalc.h +1426 -0
  94. data/ext/libxcrypt/lib/alg-gost3411-2012-ref.h +67 -0
  95. data/ext/libxcrypt/lib/alg-hmac-sha1.c +140 -0
  96. data/ext/libxcrypt/lib/alg-hmac-sha1.h +35 -0
  97. data/ext/libxcrypt/lib/alg-md4.c +270 -0
  98. data/ext/libxcrypt/lib/alg-md4.h +43 -0
  99. data/ext/libxcrypt/lib/alg-md5.c +291 -0
  100. data/ext/libxcrypt/lib/alg-md5.h +43 -0
  101. data/ext/libxcrypt/lib/alg-sha1.c +288 -0
  102. data/ext/libxcrypt/lib/alg-sha1.h +34 -0
  103. data/ext/libxcrypt/lib/alg-sha256.c +630 -0
  104. data/ext/libxcrypt/lib/alg-sha256.h +123 -0
  105. data/ext/libxcrypt/lib/alg-sha512.c +311 -0
  106. data/ext/libxcrypt/lib/alg-sha512.h +81 -0
  107. data/ext/libxcrypt/lib/alg-sm3-hmac.c +113 -0
  108. data/ext/libxcrypt/lib/alg-sm3-hmac.h +42 -0
  109. data/ext/libxcrypt/lib/alg-sm3.c +449 -0
  110. data/ext/libxcrypt/lib/alg-sm3.h +63 -0
  111. data/ext/libxcrypt/lib/alg-yescrypt-common.c +713 -0
  112. data/ext/libxcrypt/lib/alg-yescrypt-opt.c +1568 -0
  113. data/ext/libxcrypt/lib/alg-yescrypt-platform.c +106 -0
  114. data/ext/libxcrypt/lib/alg-yescrypt.h +360 -0
  115. data/ext/libxcrypt/lib/byteorder.h +164 -0
  116. data/ext/libxcrypt/lib/crypt-bcrypt.c +1061 -0
  117. data/ext/libxcrypt/lib/crypt-des-obsolete.c +215 -0
  118. data/ext/libxcrypt/lib/crypt-des.c +491 -0
  119. data/ext/libxcrypt/lib/crypt-gensalt-static.c +40 -0
  120. data/ext/libxcrypt/lib/crypt-gost-yescrypt.c +182 -0
  121. data/ext/libxcrypt/lib/crypt-md5.c +232 -0
  122. data/ext/libxcrypt/lib/crypt-nthash.c +134 -0
  123. data/ext/libxcrypt/lib/crypt-obsolete.h +40 -0
  124. data/ext/libxcrypt/lib/crypt-pbkdf1-sha1.c +260 -0
  125. data/ext/libxcrypt/lib/crypt-port.h +514 -0
  126. data/ext/libxcrypt/lib/crypt-scrypt.c +247 -0
  127. data/ext/libxcrypt/lib/crypt-sha256.c +308 -0
  128. data/ext/libxcrypt/lib/crypt-sha512.c +323 -0
  129. data/ext/libxcrypt/lib/crypt-sm3-yescrypt.c +189 -0
  130. data/ext/libxcrypt/lib/crypt-sm3.c +308 -0
  131. data/ext/libxcrypt/lib/crypt-static.c +44 -0
  132. data/ext/libxcrypt/lib/crypt-sunmd5.c +314 -0
  133. data/ext/libxcrypt/lib/crypt-yescrypt.c +177 -0
  134. data/ext/libxcrypt/lib/crypt.c +421 -0
  135. data/ext/libxcrypt/lib/crypt.h.in +249 -0
  136. data/ext/libxcrypt/lib/gen-des-tables.c +363 -0
  137. data/ext/libxcrypt/lib/hashes.conf +59 -0
  138. data/ext/libxcrypt/lib/libcrypt.map.in +48 -0
  139. data/ext/libxcrypt/lib/libcrypt.minver +97 -0
  140. data/ext/libxcrypt/lib/libxcrypt.pc.in +15 -0
  141. data/ext/libxcrypt/lib/util-base64.c +26 -0
  142. data/ext/libxcrypt/lib/util-gensalt-sha.c +88 -0
  143. data/ext/libxcrypt/lib/util-get-random-bytes.c +154 -0
  144. data/ext/libxcrypt/lib/util-make-failure-token.c +48 -0
  145. data/ext/libxcrypt/lib/util-xbzero.c +43 -0
  146. data/ext/libxcrypt/lib/util-xstrcpy.c +42 -0
  147. data/ext/libxcrypt/lib/xcrypt.h.in +58 -0
  148. data/ext/libxcrypt/libxcrypt.spec.rpkg +481 -0
  149. data/ext/libxcrypt/rpkg.conf +2 -0
  150. data/ext/libxcrypt/rpkg.macros +86 -0
  151. data/ext/libxcrypt/test/TestCommon.pm +326 -0
  152. data/ext/libxcrypt/test/alg-des.c +80 -0
  153. data/ext/libxcrypt/test/alg-gost3411-2012-hmac.c +90 -0
  154. data/ext/libxcrypt/test/alg-gost3411-2012.c +191 -0
  155. data/ext/libxcrypt/test/alg-hmac-sha1.c +187 -0
  156. data/ext/libxcrypt/test/alg-md4.c +111 -0
  157. data/ext/libxcrypt/test/alg-md5.c +134 -0
  158. data/ext/libxcrypt/test/alg-pbkdf-hmac-sha256.c +269 -0
  159. data/ext/libxcrypt/test/alg-sha1.c +111 -0
  160. data/ext/libxcrypt/test/alg-sha256.c +141 -0
  161. data/ext/libxcrypt/test/alg-sha512.c +170 -0
  162. data/ext/libxcrypt/test/alg-sm3-hmac.c +149 -0
  163. data/ext/libxcrypt/test/alg-sm3.c +168 -0
  164. data/ext/libxcrypt/test/alg-yescrypt.c +466 -0
  165. data/ext/libxcrypt/test/badsalt.c +726 -0
  166. data/ext/libxcrypt/test/badsetting.c +350 -0
  167. data/ext/libxcrypt/test/byteorder.c +254 -0
  168. data/ext/libxcrypt/test/checksalt.c +265 -0
  169. data/ext/libxcrypt/test/compile-strong-alias.c +43 -0
  170. data/ext/libxcrypt/test/crypt-badargs.c +392 -0
  171. data/ext/libxcrypt/test/crypt-gost-yescrypt.c +149 -0
  172. data/ext/libxcrypt/test/crypt-nested-call.c +180 -0
  173. data/ext/libxcrypt/test/crypt-sm3-yescrypt.c +149 -0
  174. data/ext/libxcrypt/test/crypt-too-long-phrase.c +157 -0
  175. data/ext/libxcrypt/test/des-cases.h +196 -0
  176. data/ext/libxcrypt/test/des-obsolete.c +206 -0
  177. data/ext/libxcrypt/test/des-obsolete_r.c +207 -0
  178. data/ext/libxcrypt/test/explicit-bzero.c +334 -0
  179. data/ext/libxcrypt/test/gensalt-bcrypt_x.c +54 -0
  180. data/ext/libxcrypt/test/gensalt-extradata.c +246 -0
  181. data/ext/libxcrypt/test/gensalt-nested-call.c +126 -0
  182. data/ext/libxcrypt/test/gensalt-nthash.c +65 -0
  183. data/ext/libxcrypt/test/gensalt.c +599 -0
  184. data/ext/libxcrypt/test/getrandom-fallbacks.c +295 -0
  185. data/ext/libxcrypt/test/getrandom-interface.c +211 -0
  186. data/ext/libxcrypt/test/ka-table-gen.py +945 -0
  187. data/ext/libxcrypt/test/ka-table.inc +5849 -0
  188. data/ext/libxcrypt/test/ka-tester.c +240 -0
  189. data/ext/libxcrypt/test/preferred-method.c +133 -0
  190. data/ext/libxcrypt/test/short-outbuf.c +119 -0
  191. data/ext/libxcrypt/test/special-char-salt.c +1160 -0
  192. data/ext/libxcrypt/test/symbols-compat.pl +137 -0
  193. data/ext/libxcrypt/test/symbols-renames.pl +107 -0
  194. data/ext/libxcrypt/test/symbols-static.pl +87 -0
  195. data/ext/xcrypt/xcrypt.c +9 -0
  196. data/lib/xcrypt/ffi.rb +76 -0
  197. data/lib/xcrypt/version.rb +5 -0
  198. data/lib/xcrypt.rb +89 -0
  199. metadata +267 -0
@@ -0,0 +1,137 @@
1
+ #! /usr/bin/perl
2
+ # Written by Zack Weinberg <zackw at panix.com> in 2017 and 2020.
3
+ # To the extent possible under law, Zack Weinberg has waived all
4
+ # copyright and related or neighboring rights to this work.
5
+ #
6
+ # See https://creativecommons.org/publicdomain/zero/1.0/ for further
7
+ # details.
8
+
9
+ # This test is only run if we are building a shared library intended
10
+ # to be binary backward compatible with GNU libc (libcrypt.so.1).
11
+ # It locates any installed version of libcrypt.so.1, and verifies that
12
+ # each public symbol exposed by that library is also exposed by our
13
+ # libcrypt.so.1 with a matching symbol version.
14
+ #
15
+ # Due to limitations in Automake, this program takes parameters from
16
+ # the environment:
17
+ # $lib_la - full pathname of libcrypt.la
18
+ # $SYMBOL_PREFIX - prefix, if any, added to global symbols defined from C
19
+ # $CC, $NM - names of tools to run (defaults to 'cc' and 'nm' respectively)
20
+ # $CFLAGS, $LDFLAGS - options to pass to $CC when linking (default: empty)
21
+
22
+ use v5.14; # implicit use strict, use feature ':5.14'
23
+ use warnings FATAL => 'all';
24
+ use utf8;
25
+ use open qw(:std :utf8);
26
+ no if $] >= 5.022, warnings => 'experimental::re_strict';
27
+ use if $] >= 5.022, re => 'strict';
28
+
29
+ use FindBin ();
30
+ use lib $FindBin::Bin;
31
+ use TestCommon qw(
32
+ compare_symbol_lists
33
+ ensure_C_locale
34
+ find_real_library
35
+ get_symbols
36
+ popen
37
+ sh_split
38
+ skip
39
+ subprocess_error
40
+ which
41
+ );
42
+
43
+ # Some differences between the symbols exported by heritage libcrypt.so.1
44
+ # and our libcrypt.so.1 are expected:
45
+ #
46
+ # * All of the symbols we define with GLIBC_2.xx version tags are
47
+ # compatibility symbols (nm prints only one @); naturally,
48
+ # glibc-provided libcrypt.so.1 defines some of those symbols as
49
+ # linkable symbols (two @).
50
+ #
51
+ # * Older versions of libcrypt defined five symbols as linkable,
52
+ # with the XCRYPT_2.0 version tag, which are now compatibility-only:
53
+ # crypt_gensalt_r, xcrypt, xcrypt_gensalt, xcrypt_gensalt_r, and
54
+ # xcrypt_r.
55
+ #
56
+ # This sub is applied to the symbol listing from the system-provided
57
+ # libcrypt.so.1; it edits that listing so that the comparison below
58
+ # succeeds despite any expected differences.
59
+ sub filter_expected_differences {
60
+ my $symbols = shift;
61
+ my %filtered;
62
+ my $formerly_linkable = qr{
63
+ ^ (?: crypt_gensalt_r
64
+ | xcrypt(?: _r)?
65
+ | xcrypt_gensalt(?: _r)?
66
+ ) @@
67
+ }x;
68
+ for my $s (keys %{$symbols}) {
69
+ $s =~ s/\b@@(?=GLIBC_)/@/;
70
+ $s =~ s/\b@@(?=XCRYPT_2\.0)/@/ if $s =~ $formerly_linkable;
71
+ $filtered{$s} = 1;
72
+ }
73
+ return \%filtered;
74
+ }
75
+
76
+ sub find_system_libcrypt {
77
+ # Ask the compiler whether a libcrypt.so.1 exists in its search
78
+ # path. The compiler option -print-file-name should be supported
79
+ # on all operating systems where there's an older libcrypt that we
80
+ # can be backward compatible with.
81
+ state @CC;
82
+ if (!@CC) {
83
+ @CC = which($ENV{CC} || 'cc');
84
+ skip('C compiler not available') unless @CC;
85
+ }
86
+
87
+ state @CFLAGS;
88
+ if (!@CFLAGS) {
89
+ @CFLAGS = sh_split($ENV{CFLAGS} || q{});
90
+ }
91
+ state @LDFLAGS;
92
+ if (!@LDFLAGS) {
93
+ @LDFLAGS = sh_split($ENV{LDFLAGS} || q{});
94
+ }
95
+
96
+ my $fh =
97
+ popen('-|', @CC, @CFLAGS, @LDFLAGS, '-print-file-name=libcrypt.so.1');
98
+ my $path;
99
+ {
100
+ local $/ = undef; # slurp
101
+ $path = <$fh>;
102
+ }
103
+ close $fh or subprocess_error($CC[0]);
104
+
105
+ chomp $path;
106
+ # If we get back either the empty string or the same string we put
107
+ # in, it means there is no libcrypt.so.1 on this system.
108
+ if ($path eq q{} || $path eq 'libcrypt.so.1') {
109
+ skip('no system-provided libcrypt.so.1');
110
+ }
111
+ return $path;
112
+ }
113
+
114
+ sub get_our_symbols {
115
+ return get_symbols(find_real_library(shift, 'shared'));
116
+ }
117
+
118
+ sub get_their_symbols {
119
+ return filter_expected_differences(get_symbols(find_system_libcrypt()));
120
+ }
121
+
122
+ #
123
+ # Main
124
+ #
125
+ my $lib_la = $ENV{lib_la} || '/nonexistent';
126
+ if (!-f $lib_la) {
127
+ print {*STDERR} "usage: lib_la=/path/to/library.la $0";
128
+ exit 1;
129
+ }
130
+
131
+ ensure_C_locale();
132
+ exit compare_symbol_lists(
133
+ get_our_symbols($lib_la),
134
+ get_their_symbols(),
135
+ 'symbol versions',
136
+ 1, # extra symbols are allowed
137
+ );
@@ -0,0 +1,107 @@
1
+ #! /usr/bin/perl
2
+ # Written by Zack Weinberg <zackw at panix.com> in 2017 and 2020.
3
+ # To the extent possible under law, Zack Weinberg has waived all
4
+ # copyright and related or neighboring rights to this work.
5
+ #
6
+ # See https://creativecommons.org/publicdomain/zero/1.0/ for further
7
+ # details.
8
+
9
+ # Check that all of the symbols renamed by crypt-port.h
10
+ # still appear somewhere in the source code. This test does not attempt
11
+ # to parse the source code, so it can get false negatives (e.g. a word used
12
+ # in a comment will be enough).
13
+ #
14
+ # Due to limitations in Automake, this program takes parameters from
15
+ # the environment:
16
+ # $lib_la - full pathname of libcrypt.la
17
+ # $SYMBOL_PREFIX - prefix, if any, added to global symbols defined from C
18
+ # $NM, $CPP, $CPPFLAGS - nm utility, C preprocessor, and parameters
19
+
20
+ use v5.14; # implicit use strict, use feature ':5.14'
21
+ use warnings FATAL => 'all';
22
+ use utf8;
23
+ use open qw(:std :utf8);
24
+ no if $] >= 5.022, warnings => 'experimental::re_strict';
25
+ use if $] >= 5.022, re => 'strict';
26
+
27
+ use File::Temp ();
28
+
29
+ use FindBin ();
30
+ use lib $FindBin::Bin;
31
+ use TestCommon qw(
32
+ compare_symbol_lists
33
+ ensure_C_locale
34
+ find_real_library
35
+ get_symbols
36
+ popen
37
+ sh_split
38
+ skip
39
+ subprocess_error
40
+ which
41
+ );
42
+
43
+ sub list_library_internals {
44
+ # We are only interested in symbols with the internal prefix,
45
+ # _crypt_.
46
+ return get_symbols(find_real_library(shift, 'static'),
47
+ sub { $_[0] =~ /^_crypt_/ });
48
+ }
49
+
50
+ sub list_symbol_renames {
51
+ state @CPP;
52
+ if (!@CPP) {
53
+ @CPP = which($ENV{CPP} || 'cc -E');
54
+ skip('C compiler not available') unless @CPP;
55
+ }
56
+ state @CPPFLAGS;
57
+ if (!@CPPFLAGS) {
58
+ @CPPFLAGS = sh_split($ENV{CPPFLAGS} || q{});
59
+ }
60
+
61
+ my $tmp = File::Temp->new(
62
+ DIR => '.',
63
+ TEMPLATE => 'symbols-renames-XXXXXX',
64
+ SUFFIX => '.c',
65
+ EXLOCK => 0,
66
+ );
67
+ print {$tmp} qq{#include "crypt-port.h"\n};
68
+
69
+ my $fh = popen('-|', @CPP, @CPPFLAGS, '-dD', $tmp->filename);
70
+ local $_;
71
+ my %symbols;
72
+ my $pp_define = qr{
73
+ ^\#define \s+
74
+ [a-zA-Z_][a-zA-Z0-9_(),]* \s+
75
+ (_crypt_[a-zA-Z0-9_]*) \b
76
+ }x;
77
+ while (<$fh>) {
78
+ chomp;
79
+ s/\s+$//;
80
+ if ($_ =~ $pp_define) {
81
+ print {*STDERR} "| $1\n";
82
+ $symbols{$1} = 1;
83
+ }
84
+ }
85
+ close $fh or subprocess_error($CPP[0]);
86
+ return \%symbols;
87
+ }
88
+
89
+ #
90
+ # Main
91
+ #
92
+ my $lib_la = $ENV{lib_la} || '/nonexistent';
93
+ if (!-f $lib_la) {
94
+ print {*STDERR} "usage: lib_la=/path/to/library.la $0";
95
+ exit 1;
96
+ }
97
+ if (($ENV{HAVE_CPP_dD} // 'yes') eq 'no') {
98
+ skip('cpp -dD not available');
99
+ }
100
+
101
+ ensure_C_locale();
102
+ exit compare_symbol_lists(
103
+ list_library_internals($lib_la),
104
+ list_symbol_renames(),
105
+ 'renames',
106
+ 0, # extra symbols not allowed
107
+ );
@@ -0,0 +1,87 @@
1
+ #! /usr/bin/perl
2
+ # Written by Zack Weinberg <zackw at panix.com> in 2017 and 2020.
3
+ # To the extent possible under law, Zack Weinberg has waived all
4
+ # copyright and related or neighboring rights to this work.
5
+ #
6
+ # See https://creativecommons.org/publicdomain/zero/1.0/ for further
7
+ # details.
8
+
9
+ # Test that all global symbols in the static version of the library
10
+ # (libcrypt.a) are either listed as global and supported for new code
11
+ # in libcrypt.map.in, or begin with a _crypt prefix. Also test that
12
+ # all of the global, supported for new code, symbols mentioned in
13
+ # libcrypt.map.in are in fact defined.
14
+ #
15
+ # Due to limitations in Automake, this program takes parameters from
16
+ # the environment:
17
+ # $lib_la - full pathname of libcrypt.la
18
+ # $lib_map - full pathname of libcrypt.map.in
19
+ # $SYMBOL_PREFIX - prefix, if any, added to global symbols defined from C
20
+ # $NM, $CPP, $CPPFLAGS - nm utility, C preprocessor, and parameters
21
+
22
+ use v5.14; # implicit use strict, use feature ':5.14'
23
+ use warnings FATAL => 'all';
24
+ use utf8;
25
+ use open qw(:std :utf8);
26
+ no if $] >= 5.022, warnings => 'experimental::re_strict';
27
+ use if $] >= 5.022, re => 'strict';
28
+
29
+ use FindBin ();
30
+ use lib $FindBin::Bin;
31
+ use TestCommon qw(
32
+ error
33
+ ensure_C_locale
34
+ find_real_library
35
+ get_symbols
36
+ compare_symbol_lists
37
+ );
38
+
39
+ my $symbol_prefix = $ENV{SYMBOL_PREFIX} || q{};
40
+
41
+ sub list_library_globals {
42
+ # Symbols that begin with _crypt_ are private to the library.
43
+ # Symbols that begin with _[_A-Y] are private to the C
44
+ # implementation. All other symbols (including any that begin
45
+ # with _Z, which are C++ mangled names) are part of the library's
46
+ # public interface.
47
+ return get_symbols(
48
+ find_real_library(shift, 'static'),
49
+ sub { $_[0] !~ /^_(?:[_A-Y]|crypt_)/ },
50
+ );
51
+ }
52
+
53
+ sub list_expected_globals {
54
+ my ($lib_map) = @_;
55
+ open my $fh, '<', $lib_map
56
+ or error("$lib_map: $!");
57
+
58
+ local $_;
59
+ my %symbols;
60
+ while (<$fh>) {
61
+ chomp;
62
+ s/\s+$//;
63
+ next if /^($|#|%chain\b)/;
64
+
65
+ my @fields = split;
66
+ $symbols{$fields[0]} = 1 if $fields[1] ne '-';
67
+ }
68
+ return \%symbols;
69
+ }
70
+
71
+ #
72
+ # Main
73
+ #
74
+ my $lib_la = $ENV{lib_la} || '/nonexistent';
75
+ my $lib_map = $ENV{lib_map} || '/nonexistent';
76
+ if (!-f $lib_la || !-f $lib_map) {
77
+ print {*STDERR} "usage: lib_la=/p/lib.la lib_map=/p/lib.map $0";
78
+ exit 1;
79
+ }
80
+
81
+ ensure_C_locale();
82
+ exit compare_symbol_lists(
83
+ list_library_globals($lib_la),
84
+ list_expected_globals($lib_map),
85
+ 'globals',
86
+ 0, # extra symbols not allowed
87
+ );
@@ -0,0 +1,9 @@
1
+ /*
2
+ * xcrypt.c — compilation stub for ffi-compiler.
3
+ *
4
+ * The actual implementation lives in libxcrypt (ext/libxcrypt), which is
5
+ * linked statically into this shared library at build time. Ruby code
6
+ * reaches the libxcrypt API through Ruby-FFI (see lib/xcrypt/ffi.rb); no
7
+ * wrapper functions are needed here.
8
+ */
9
+ #include "crypt.h"
data/lib/xcrypt/ffi.rb ADDED
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+ require "ffi-compiler/loader"
5
+
6
+ module XCrypt
7
+ # Low-level FFI bindings for libxcrypt.
8
+ #
9
+ # Consumers should use the high-level {XCrypt} module methods instead of
10
+ # calling into this module directly.
11
+ #
12
+ # The shared library loaded here is compiled from the libxcrypt submodule
13
+ # (ext/libxcrypt) via ffi-compiler. Run <tt>bundle exec rake compile</tt>
14
+ # to build it before loading this gem.
15
+ module FFI
16
+ extend ::FFI::Library
17
+
18
+ # Size constants mirrored from <crypt.h>.
19
+ CRYPT_OUTPUT_SIZE = 384
20
+ CRYPT_MAX_PASSPHRASE_SIZE = 512
21
+ CRYPT_GENSALT_OUTPUT_SIZE = 192
22
+ CRYPT_DATA_RESERVED_SIZE = 767
23
+ CRYPT_DATA_INTERNAL_SIZE = 30_720
24
+
25
+ # sizeof(struct crypt_data) == 32768 bytes, as guaranteed by the header.
26
+ CRYPT_DATA_SIZE = 32_768
27
+
28
+ # crypt_checksalt(3) return codes.
29
+ CRYPT_SALT_OK = 0
30
+ CRYPT_SALT_INVALID = 1
31
+ CRYPT_SALT_METHOD_DISABLED = 2
32
+ CRYPT_SALT_METHOD_LEGACY = 3
33
+ CRYPT_SALT_TOO_CHEAP = 4
34
+
35
+ # Load the native extension compiled from the libxcrypt submodule.
36
+ # FFI::Compiler::Loader searches for lib<arch>-<os>/libxcrypt.{bundle,so}
37
+ # relative to this file's location.
38
+ begin
39
+ ffi_lib ::FFI::Compiler::Loader.find("xcrypt")
40
+ rescue LoadError
41
+ raise LoadError,
42
+ "XCrypt native extension not found. " \
43
+ "Build it with: rake compile"
44
+ end
45
+
46
+ # char *crypt_rn(const char *phrase, const char *setting,
47
+ # void *data, int size)
48
+ #
49
+ # Thread-safe variant that writes to a caller-supplied buffer. Returns
50
+ # NULL on error instead of a magic error string.
51
+ attach_function :crypt_rn, [:string, :string, :pointer, :int], :pointer
52
+
53
+ # char *crypt_gensalt_rn(const char *prefix, unsigned long count,
54
+ # const char *rbytes, int nrbytes,
55
+ # char *output, int output_size)
56
+ #
57
+ # Thread-safe salt generator that writes to a caller-supplied buffer.
58
+ # Pass NULL for rbytes to let the library obtain entropy from the OS.
59
+ attach_function :crypt_gensalt_rn,
60
+ [:string, :ulong, :pointer, :int, :pointer, :int],
61
+ :pointer
62
+
63
+ # int crypt_checksalt(const char *setting)
64
+ #
65
+ # Inspects a setting string and reports whether it is valid.
66
+ attach_function :crypt_checksalt, [:string], :int
67
+
68
+ # const char *crypt_preferred_method(void)
69
+ #
70
+ # Returns the prefix string of the library's preferred (strongest)
71
+ # hashing method.
72
+ attach_function :crypt_preferred_method, [], :string
73
+ end
74
+
75
+ private_constant :FFI
76
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XCrypt
4
+ VERSION = "0.1.0"
5
+ end
data/lib/xcrypt.rb ADDED
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module XCrypt
4
+ require "xcrypt/version"
5
+ require "xcrypt/ffi"
6
+
7
+ Error ||= Class.new(StandardError)
8
+
9
+ ALGORITHMS = {
10
+ yescrypt: "$y$",
11
+ gost_yescrypt: "$gy$",
12
+ scrypt: "$7$",
13
+ bcrypt: "$2b$",
14
+ sha512: "$6$",
15
+ sha256: "$5$",
16
+ sha1: "$sha1$",
17
+ sun_md5: "$md5",
18
+ md5: "$1$",
19
+ bsdi_des: "_",
20
+ des: "",
21
+ }.freeze
22
+
23
+ PREFIXES = ALGORITHMS.invert.freeze
24
+ private_constant :ALGORITHMS, :PREFIXES
25
+
26
+ extend self
27
+
28
+ ALGORITHMS.each_key do |algorithm|
29
+ define_method(algorithm) do |phrase, setting = nil, cost: nil|
30
+ if setting
31
+ setting_algorithm = detect_algorithm(setting)
32
+ if setting_algorithm != algorithm
33
+ raise ArgumentError, "setting algorithm #{setting_algorithm.inspect} does not match expected #{algorithm.inspect}"
34
+ end
35
+ end
36
+ crypt(phrase, setting, algorithm:, cost:)
37
+ end
38
+ end
39
+
40
+ def algorithms = ALGORITHMS.keys
41
+
42
+ def detect_algorithm(setting) = PREFIXES[setting[/\A\$\w+\$?|_/].to_s]
43
+
44
+ def crypt(phrase, setting = nil, algorithm: nil, cost: nil)
45
+ setting, algorithm = nil, setting if setting.is_a? Symbol
46
+ setting ||= generate_setting(algorithm, cost:)
47
+ data = ::FFI::MemoryPointer.new(:uint8, FFI::CRYPT_DATA_SIZE)
48
+ result_ptr = FFI.crypt_rn(phrase, setting, data, FFI::CRYPT_DATA_SIZE)
49
+ raise Error, "crypt failed: invalid setting or unsupported algorithm" if result_ptr.null?
50
+ result_ptr.read_string
51
+ ensure
52
+ data&.clear
53
+ end
54
+
55
+ def verify(phrase, hash)
56
+ return false if hash.nil? || hash.empty? || hash.start_with?("*")
57
+ result = crypt(phrase, hash)
58
+ secure_compare(result, hash)
59
+ rescue Error
60
+ false
61
+ end
62
+
63
+ def generate_setting(algorithm = nil, cost: nil)
64
+ prefix = ALGORITHMS.fetch(algorithm) { raise ArgumentError, "unknown algorithm: #{algorithm.inspect}" } if algorithm
65
+ cost ||= 0
66
+
67
+ output = ::FFI::MemoryPointer.new(:char, FFI::CRYPT_GENSALT_OUTPUT_SIZE)
68
+ result_ptr = FFI.crypt_gensalt_rn(prefix, cost, nil, 0, output, FFI::CRYPT_GENSALT_OUTPUT_SIZE)
69
+ raise Error, "crypt_gensalt failed: unknown prefix or unsupported algorithm" if result_ptr.null?
70
+
71
+ result_ptr.read_string
72
+ end
73
+
74
+ private
75
+
76
+ def secure_compare(trusted, untrusted)
77
+ return false unless trusted.respond_to? :to_str and trusted = trusted.to_str.b
78
+ return false unless untrusted.respond_to? :to_str and untrusted = untrusted.to_str.b
79
+
80
+ # avoid ability for attacker to guess length of string by timing attack
81
+ comparable = trusted[0, untrusted.bytesize].ljust(untrusted.bytesize, "\0".b)
82
+
83
+ result = defined?(OpenSSL.fixed_length_secure_compare) ?
84
+ OpenSSL.fixed_length_secure_compare(comparable, untrusted) :
85
+ comparable.each_byte.zip(untrusted.each_byte).reduce(0) { |acc, (a, b)| acc | (a ^ b) }.zero?
86
+
87
+ trusted.bytesize == untrusted.bytesize and result
88
+ end
89
+ end