/src/ez_crypt.erl

https://github.com/joearms/crypto_tutorial · Erlang · 205 lines · 157 code · 42 blank · 6 comment · 1 complexity · 5a925dfe35b35dc03f903092fd47ee94 MD5 · raw file

  1. -module(ez_crypt).
  2. -export([
  3. aes_decrypt/2,
  4. aes_encrypt/2,
  5. bsize/1,
  6. decrypt_message/3,
  7. encrypt_message/2,
  8. file2sha/1,
  9. is_probably_prime/1,
  10. make_k_bit_prime/1,
  11. make_rsa_key/1,
  12. make_rsa_keyfiles/4,
  13. mod_pow/3,
  14. random_session_key/0,
  15. read_private_key/2,
  16. read_public_key/1,
  17. rsa_decrypt/2,
  18. rsa_encrypt/2,
  19. sha1_checksum_of_file/1,
  20. sign_current_dir/0,
  21. sign_file/3,
  22. stream_decrypt/2,
  23. stream_encrypt/2,
  24. stream_init/1,
  25. validate_file/2,
  26. validate_this_dir/0
  27. ]).
  28. -spec mod_pow(N::integer(), P::integer(), M::integer()) -> R::integer().
  29. -spec make_k_bit_prime(Nbits::integer()) -> Prime::integer().
  30. %% compute N^P mod N
  31. mod_pow(N, P, M) -> ez_crypt_math:mod_pow(N, P, M).
  32. make_k_bit_prime(K) -> ez_crypt_primes:make_k_bit_prime(K).
  33. bsize(N) -> ez_crypt_math:bsize(N).
  34. make_rsa_key(LenInBits) -> ez_crypt_math:make_rsa_keypair(LenInBits).
  35. is_probably_prime(X) -> ez_crypt_miller_rabin:is_probably_prime(X).
  36. %% START:make_rsa_keyfiles
  37. make_rsa_keyfiles(Name, Email, Len, Password) ->
  38. {E,D,N} = make_rsa_key(Len),
  39. {ok, S} = file:open(Name ++ ".pub", [write]),
  40. io:format(S,"~p.~n",
  41. [#{type=>public_key,
  42. email => Email,
  43. e => E,
  44. n => N}]),
  45. file:close(S),
  46. Term = #{type => private_key,
  47. name => Name,
  48. email => Email,
  49. e => E,
  50. d => D,
  51. n => N},
  52. Bin1 = term_to_binary(Term),
  53. Bin2 = aes_encrypt(Password, Bin1),
  54. {ok, S1} = file:open(Name ++ ".pri", [write]),
  55. io:format(S1,"~p.~n",
  56. [#{type=>encrypted_private_key,
  57. value => Bin2}]),
  58. file:close(S1).
  59. %% END:make_rsa_keyfiles
  60. -spec random_session_key() -> binary().
  61. random_session_key() ->
  62. crypto:strong_rand_bytes(20).
  63. sign_file(File, PrivateKeyFile, Password) ->
  64. SHA = sha1_checksum_of_file(File),
  65. PriKey = read_private_key(PrivateKeyFile, Password),
  66. Sig = rsa_encrypt(PriKey, SHA),
  67. file:write_file(File ++ ".sig", term_to_binary(Sig)).
  68. validate_file(PubKeyFile, File) ->
  69. SHA1 = sha1_checksum_of_file(File),
  70. {ok, Bin} = file:read_file(File ++ ".sig"),
  71. Sig = binary_to_term(Bin),
  72. PubKey = read_public_key(PubKeyFile),
  73. io:format("PubKey=~p~n",[PubKey]),
  74. SHA2 = rsa_decrypt(PubKey, Sig),
  75. Ret = case SHA1 of
  76. SHA2 -> true;
  77. _ -> false
  78. end,
  79. io:format("Validate:~s ~p~n",[File, Ret]),
  80. Ret.
  81. sha1_checksum_of_file(File) ->
  82. {ok, Bin} = file:read_file(File),
  83. sha1_checksum(Bin).
  84. sha1_checksum(X) ->
  85. crypto:hash(sha, <<X/binary>>).
  86. rsa_encrypt({E,N}=Key, Bin) when is_integer(E),
  87. is_integer(N),
  88. is_binary(Bin) ->
  89. ez_crypt_rsa:encrypt_3(Key, Bin).
  90. rsa_decrypt({E,N}=Key, B) when is_integer(E),
  91. is_integer(N),
  92. is_binary(B) ->
  93. ez_crypt_rsa:decrypt_3(Key, B).
  94. sign_current_dir() ->
  95. F = erl_files(),
  96. L = [{file,I,sha1_checksum_of_file(I)} || I <- F],
  97. io:format("L=~p~n",[L]),
  98. write_term("catalog", L),
  99. sign_file("catalog", "joe.pri", <<"verysecret">>).
  100. erl_files() ->
  101. F = filelib:wildcard("*.erl"),
  102. lists:filter(fun(".#" ++ _) -> false;
  103. (_) -> true
  104. end, F).
  105. validate_this_dir() ->
  106. validate_file("joe.pub","catalog").
  107. write_term(File, X) ->
  108. {ok, H} = file:open(File,[write]),
  109. io:format(H, "~p.~n",[X]),
  110. file:close(H).
  111. aes_encrypt(Password, Bin) when is_binary(Password),
  112. is_binary(Bin) ->
  113. ez_crypt_aes:encrypt(Password, Bin).
  114. aes_decrypt(Password, Bin) when is_binary(Password),
  115. is_binary(Bin) ->
  116. ez_crypt_aes:decrypt(Password, Bin).
  117. read_private_key(File, Password) ->
  118. {ok, [#{type := encrypted_private_key,
  119. value := Bin}]} = file:consult(File),
  120. Bin1 = aes_decrypt(Password, Bin),
  121. Term = binary_to_term(Bin1),
  122. #{d := D, n:= N} = Term,
  123. {D, N}.
  124. read_public_key(File) ->
  125. {ok, [#{type := public_key,
  126. e := E, n := N}]} = file:consult(File),
  127. {E, N}.
  128. encrypt_message(Who, Msg) ->
  129. Ran = random_session_key(),
  130. EncMessage = aes_encrypt(Ran, Msg),
  131. PubKey = read_public_key(Who),
  132. EncKey = rsa_encrypt(PubKey, Ran),
  133. term_to_binary({EncKey,EncMessage}).
  134. decrypt_message(Who, Password, Bin) ->
  135. {EncKey,EncMessage} = binary_to_term(Bin),
  136. PriKey = read_private_key(Who, Password),
  137. Key = rsa_decrypt(PriKey, EncKey),
  138. Message = aes_decrypt(Key, EncMessage),
  139. Message.
  140. stream_init(Password) ->
  141. crypto:stream_init(rc4, Password).
  142. stream_encrypt(Key, Bin) ->
  143. crypto:stream_encrypt(Key, Bin).
  144. stream_decrypt(Key, Bin) ->
  145. crypto:stream_decrypt(Key, Bin).
  146. %% START:filehash
  147. file2sha(File) ->
  148. hash_file(File, sha).
  149. hash_file(File, Method) ->
  150. % the file can be huge so read it in chunks
  151. case file:open(File, [binary,raw,read]) of
  152. {ok, P} -> hash_loop(P, crypto:hash_init(Method));
  153. Error -> Error
  154. end.
  155. hash_loop(P, C) ->
  156. case file:read(P, 4096) of
  157. {ok, Bin} ->
  158. hash_loop(P, crypto:hash_update(C, Bin));
  159. eof ->
  160. file:close(P),
  161. {ok, crypto:hash_final(C)}
  162. end.
  163. %% END:filehash