md4.odin 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package vendor_md4
  2. /*
  3. Copyright 2021 zhibog
  4. Made available under the BSD-3 license.
  5. List of contributors:
  6. zhibog: Initial implementation.
  7. Interface for the MD4 hashing algorithm.
  8. The hash will be computed via bindings to the Botan crypto library
  9. */
  10. import "core:os"
  11. import "core:io"
  12. import botan "../bindings"
  13. /*
  14. High level API
  15. */
  16. DIGEST_SIZE :: 16
  17. // hash_string will hash the given input and return the
  18. // computed hash
  19. hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte {
  20. return hash_bytes(transmute([]byte)(data))
  21. }
  22. // hash_bytes will hash the given input and return the
  23. // computed hash
  24. hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte {
  25. hash: [DIGEST_SIZE]byte
  26. ctx: botan.hash_t
  27. botan.hash_init(&ctx, botan.HASH_MD4, 0)
  28. botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data)))
  29. botan.hash_final(ctx, &hash[0])
  30. botan.hash_destroy(ctx)
  31. return hash
  32. }
  33. // hash_string_to_buffer will hash the given input and assign the
  34. // computed hash to the second parameter.
  35. // It requires that the destination buffer is at least as big as the digest size
  36. hash_string_to_buffer :: proc(data: string, hash: []byte) {
  37. hash_bytes_to_buffer(transmute([]byte)(data), hash)
  38. }
  39. // hash_bytes_to_buffer will hash the given input and write the
  40. // computed hash into the second parameter.
  41. // It requires that the destination buffer is at least as big as the digest size
  42. hash_bytes_to_buffer :: proc(data, hash: []byte) {
  43. assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size")
  44. ctx: botan.hash_t
  45. botan.hash_init(&ctx, botan.HASH_MD4, 0)
  46. botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data)))
  47. botan.hash_final(ctx, &hash[0])
  48. botan.hash_destroy(ctx)
  49. }
  50. // hash_stream will read the stream in chunks and compute a
  51. // hash from its contents
  52. hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
  53. hash: [DIGEST_SIZE]byte
  54. ctx: botan.hash_t
  55. botan.hash_init(&ctx, botan.HASH_MD4, 0)
  56. buf := make([]byte, 512)
  57. defer delete(buf)
  58. i := 1
  59. for i > 0 {
  60. i, _ = s->impl_read(buf)
  61. if i > 0 {
  62. botan.hash_update(ctx, len(buf) == 0 ? nil : &buf[0], uint(i))
  63. }
  64. }
  65. botan.hash_final(ctx, &hash[0])
  66. botan.hash_destroy(ctx)
  67. return hash, true
  68. }
  69. // hash_file will read the file provided by the given handle
  70. // and compute a hash
  71. hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
  72. if !load_at_once {
  73. return hash_stream(os.stream_from_handle(hd))
  74. } else {
  75. if buf, ok := os.read_entire_file(hd); ok {
  76. return hash_bytes(buf[:]), ok
  77. }
  78. }
  79. return [DIGEST_SIZE]byte{}, false
  80. }
  81. hash :: proc {
  82. hash_stream,
  83. hash_file,
  84. hash_bytes,
  85. hash_string,
  86. hash_bytes_to_buffer,
  87. hash_string_to_buffer,
  88. }
  89. /*
  90. Low level API
  91. */
  92. Md4_Context :: botan.hash_t
  93. init :: proc "contextless" (ctx: ^botan.hash_t) {
  94. botan.hash_init(ctx, botan.HASH_MD4, 0)
  95. }
  96. update :: proc "contextless" (ctx: ^botan.hash_t, data: []byte) {
  97. botan.hash_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data)))
  98. }
  99. final :: proc "contextless" (ctx: ^botan.hash_t, hash: []byte) {
  100. botan.hash_final(ctx^, &hash[0])
  101. botan.hash_destroy(ctx^)
  102. }