Current section
Files
Jump to
Current section
Files
lib/safetybox.ex
defmodule Safetybox do
alias Cryptex.KeyGenerator, as: K
alias Cryptex.MessageEncryptor, as: E
alias Cryptex.MessageVerifier, as: V
@global_salt "4Yw7kLLAjFfxtqHzttpRhmPrEqqXqqrMHdgmcgUNDq"
@global_secret "FzxZRcf3xHxerDWXECwpWJVu2dwfyagTyPHmXcVpkv"
@moduledoc """
# Safetybox a collection of security oriented functions
# This is oriented towards individuals that store passwords
# directly in their code, or some other not-so-hard-to-find location
## Dependency
{ :safetybox, "~> 0.1" }
## Usage
### API
pwd = Safetybox.encrypt("helloworld")
Safetybox.is_decrypted("goodbyeworld", pwd) # > returns false
Safetybox.is_decrypted("helloworld", pwd) # > returns true
## Author
Copyright © 2014 Andrew Forward
@a4word, aforward@gmail.com
Licensed under MIT.
"""
# Taken from https://gist.github.com/10nin/5713366
def encrypt(nil), do: encrypt("")
@doc """
Convert a plaintext string into an encrypted string, for example
Safetybox.encrypt("helloworld")
"""
def encrypt(plaintext) do
:crypto.hash(:md5, plaintext)
|> :erlang.bitstring_to_list
|> Enum.map(&(:io_lib.format("~2.16.0b", [&1])))
|> List.flatten
|> :erlang.list_to_bitstring
end
@doc """
If you don't yet need a secret or a salt (e.g. very early prototype), but you want some thigns encrypted
then use the :default secret. Better than nothing, but not much.
Safetybox.encrypt("helloworld", :default)
"""
def encrypt(plaintext, :default), do: encrypt(plaintext, @global_secret, @global_salt)
@doc """
One tiny secret for a developer, one giant leap in security. Pick a secret within your application
(or ENV variable), to better prevent your strings being decrypted
Safetybox.encrypt("helloworld","mysecretkey")
"""
def encrypt(plaintext, secret), do: encrypt(plaintext, secret, @global_salt)
@doc """
Convert a plaintext string into a decryptable string by providing a secret
Safetybox.encrypt("helloworld","mysecretkey", "mysecretsalt")
"""
def encrypt(plaintext, secret, salt) do
secret
|> crypt(salt)
|> E.encrypt_and_sign(plaintext)
end
@doc """
Decrypt some obscure text that was generated by encrypt
enc = Safetybox.encrypt("helloworld")
Safetybox.decrypt(env)
"""
def decrypt(obscuretext), do: decrypt(obscuretext, @global_secret, @global_salt)
@doc """
Decrypt some obscure text that was generated by encrypt
enc = Safetybox.encrypt("helloworld")
Safetybox.decrypt(env)
"""
def decrypt(obscuretext, secret), do: decrypt(obscuretext, secret, @global_salt)
@doc """
Take an encrypted string, and convert it back to plaintext, must use the same secret and salt
enc = Safetybox.encrypt("helloworld","mysecretkey", "mysecretsalt")
Safetybox.encrypt("helloworld","mysecretkey", "mysecretsalt")
"""
def decrypt(obscuretext, secret, salt) do
secret
|> crypt(salt)
|> decrypt_and_verify(obscuretext)
end
@doc """
Compare a plaintext string to it's encrypted version to test if they match.
Safetybox.is_decrypted("helloworld", "dasdf!@#CASD")
"""
def is_decrypted(plaintext, encrypted), do: encrypt(plaintext) == encrypted
defp crypt(secret, salt) do
secret
|> K.generate(salt)
|> E.new(K.generate(secret, "signed #{salt}"))
end
defp decrypt_and_verify(cryptor, obscuretext) do
case V.verify(cryptor.sign_secret, obscuretext, :null) do
:error -> :error
{:ok, _unsigned} -> E.decrypt_and_verify(cryptor, obscuretext)
end
end
end