md5.t 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #!perl -T
  2. use utf8;
  3. use 5.006;
  4. use strict;
  5. use warnings;
  6. use Test::More;
  7. plan tests => 8;
  8. use Sidef;
  9. my $code = <<'EOT';
  10. class MD5(String msg) {
  11. method init {
  12. msg = msg.bytes
  13. }
  14. const FGHI = [
  15. {|a,b,c| (a & b) | (~a & c) },
  16. {|a,b,c| (a & c) | (b & ~c) },
  17. {|a,b,c| (a ^ b ^ c) },
  18. {|a,b,c| (b ^ (a | ~c)) },
  19. ]
  20. const S = [
  21. [7, 12, 17, 22] * 4,
  22. [5, 9, 14, 20] * 4,
  23. [4, 11, 16, 23] * 4,
  24. [6, 10, 15, 21] * 4,
  25. ].flat
  26. const T = 64.of {|i| floor(abs(sin(i+1)) * 1<<32) }
  27. const K = [
  28. ^16 -> map {|n| n },
  29. ^16 -> map {|n| (5*n + 1) % 16 },
  30. ^16 -> map {|n| (3*n + 5) % 16 },
  31. ^16 -> map {|n| (7*n ) % 16 },
  32. ].flat
  33. func radix(Number b, Array a) {
  34. ^a -> sum_by {|i| b**i * a[i] }
  35. }
  36. func little_endian(Number w, Number n, Array v) {
  37. var step1 = (^n »*» w)
  38. var step2 = (v ~X>> step1)
  39. step2 »%» (1 << w)
  40. }
  41. func block(Number a, Number b) { (a + b) & 0xffffffff }
  42. func srble(Number a, Number n) { (a << n) & 0xffffffff | (a >> (32-n)) }
  43. func md5_pad(msg) {
  44. var bits = 8*msg.len
  45. var padded = [msg..., 128, [0] * (-(floor(bits / 8) + 1 + 8) % 64)].flat
  46. gather {
  47. padded.each_slice(4, {|*a|
  48. take(radix(256, a))
  49. })
  50. take(little_endian(32, 2, [bits]))
  51. }.flat
  52. }
  53. func md5_block(Array H, Array X) {
  54. var (A, B, C, D) = H...
  55. for i in ^64 {
  56. (A, B, C, D) = (D,
  57. block(B, srble(
  58. block(
  59. block(
  60. block(A, FGHI[floor(i / 16)](B, C, D)), T[i]
  61. ), X[K[i]]
  62. ), S[i])
  63. ), B, C)
  64. }
  65. for k,v in ([A, B, C, D].kv) {
  66. H[k] = block(H[k], v)
  67. }
  68. return H
  69. }
  70. method md5_hex {
  71. self.md5.map {|n| '%02x' % n }.join
  72. }
  73. method md5 {
  74. var M = md5_pad(msg)
  75. var H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
  76. for i in (range(0, M.end, 16)) {
  77. md5_block(H, M.slice(i, 16))
  78. }
  79. little_endian(8, 4, H)
  80. }
  81. }
  82. var tests = [
  83. ['d41d8cd98f00b204e9800998ecf8427e', ''],
  84. ['0cc175b9c0f1b6a831c399e269772661', 'a'],
  85. ['900150983cd24fb0d6963f7d28e17f72', 'abc'],
  86. ['f96b697d7cb7938d525a2f31aaf161d0', 'message digest'],
  87. ['c3fcd3d76192e4007dfb496cca67e13b', 'abcdefghijklmnopqrstuvwxyz'],
  88. ['d174ab98d277d9f5a5611c2c9f419d9f', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'],
  89. ['57edf4a22be3c955ac49da2e2107b67a', '12345678901234567890123456789012345678901234567890123456789012345678901234567890'],
  90. ]
  91. var a = []
  92. for md5,msg in tests {
  93. var hash = MD5(msg).md5_hex
  94. a << hash
  95. if (hash != md5) {
  96. warn "\tExpected: #{md5}, but got #{hash}"
  97. }
  98. }
  99. a.join(' ')
  100. EOT
  101. my @md5 = qw(
  102. d41d8cd98f00b204e9800998ecf8427e
  103. 0cc175b9c0f1b6a831c399e269772661
  104. 900150983cd24fb0d6963f7d28e17f72
  105. f96b697d7cb7938d525a2f31aaf161d0
  106. c3fcd3d76192e4007dfb496cca67e13b
  107. d174ab98d277d9f5a5611c2c9f419d9f
  108. 57edf4a22be3c955ac49da2e2107b67a
  109. );
  110. my $sidef = Sidef->new(name => "md5");
  111. my $result = $sidef->execute_code($code);
  112. foreach my $md5 (split(' ', "$result")) {
  113. is($md5, shift(@md5));
  114. }
  115. ok(!@md5);