-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update to new major version of elm-sha1 (#5)
* Bump elm-sha1 dependency * Fix typo * Make elm-verify-examples work * Use elm-sha1 2.0.0 * Favor use of Bytes over List Int * Remove unused dependencies * Use Key/String instead of KeyBytes/MessageBytes * KeyBytes/MessageBytes didn't make sense given refactorings * Rename normalizeKey to makeKey (fits better with refactorings) * Remove unnecessary `Result`s * `toHex` and `toBase64` can never be `Err` * Keep hex form in lower case, as is canonical NOTE: This breaks the API, so is a MAJOR update * patch version bump * major version bump * Add note to README about testing * Rename toIntList to toByteValues * Allow for messages and keys to be made from Bytes or Strings
- Loading branch information
Showing
8 changed files
with
202 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
elm-stuff | ||
tests/elm-verify-examples.json | ||
/elm-stuff | ||
/tests/VerifyExamples/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,213 +1,150 @@ | ||
module HmacSha1 exposing | ||
( Digest, digest | ||
, toBytes, toIntList, toHex, toBase64 | ||
( Digest, fromString, fromBytes | ||
, toBytes, toByteValues, toHex, toBase64 | ||
) | ||
|
||
{-| Computes a Hash-based Message Authentication Code (HMAC) using the SHA-1 hash function | ||
@docs Digest, digest | ||
@docs Digest, fromString, fromBytes | ||
# Representation | ||
@docs toBytes, toIntList, toHex, toBase64 | ||
@docs toBytes, toByteValues, toHex, toBase64 | ||
-} | ||
|
||
import Base16 | ||
import Base64 | ||
import Bitwise | ||
import Bytes exposing (Bytes) | ||
import Bytes exposing (Bytes, Endianness(..)) | ||
import Bytes.Decode as Decode exposing (Decoder) | ||
import Bytes.Encode as Encode exposing (Encoder) | ||
import Internals exposing (Key(..), bytesToInts, stringToInts) | ||
import SHA1 | ||
import Word.Bytes as Bytes | ||
|
||
|
||
{-| A HMAC-SHA1 digest. | ||
{-| An HMAC-SHA1 digest. | ||
-} | ||
type Digest | ||
= Digest (List Int) | ||
= Digest SHA1.Digest | ||
|
||
|
||
{-| Pass a Key and a Message to compute a Digest | ||
{-| Pass a Key and your message as a String to compute a Digest | ||
digest "key" "The quick brown fox jumps over the lazy dog" | ||
import HmacSha1.Key as Key | ||
"The quick brown fox jumps over the lazy dog" | ||
|> fromString (Key.fromString "key") | ||
|> toHex | ||
--> Ok "DE7C9B85B8B78AA6BC8A7A36F70A90701C9DB4D9" | ||
--> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" | ||
digest "key" "The quick brown fox jumps over the lazy dog" | ||
"The quick brown fox jumps over the lazy dog" | ||
|> fromString (Key.fromString "key") | ||
|> toBase64 | ||
--> Ok "3nybhbi3iqa8ino29wqQcBydtNk=" | ||
-} | ||
digest : String -> String -> Digest | ||
digest key message = | ||
let | ||
normalizedKey = | ||
keyToBytes key | ||
|> normalizeKey | ||
|
||
messageBytes = | ||
messageToBytes message | ||
in | ||
hmac normalizedKey messageBytes | ||
|> Digest | ||
|
||
|
||
{-| Convert a Digest into [elm/bytes](https://package.elm-lang.org/packages/elm/bytes/latest/) Bytes. | ||
You can use this to map it to your own representations. I use it to convert it to | ||
Base16 and Base64 string representations. | ||
toBytes (digest "key" "message") | ||
--> <80 bytes> | ||
--> "3nybhbi3iqa8ino29wqQcBydtNk=" | ||
-} | ||
toBytes : Digest -> Bytes | ||
toBytes (Digest data) = | ||
listToBytes data | ||
|
||
fromString : Key -> String -> Digest | ||
fromString = | ||
usingEncoder Encode.string | ||
|
||
{-| Convert a Digest into a List of Integers. Sometimes you will want to have the | ||
Byte representation as a list of integers. | ||
|
||
toIntList (digest "key" "message") | ||
|> toIntList | ||
--> [32,136,223,116,213,242,20,107,72,20,108,175,73,101,55,126,157,11,227,164] | ||
-} | ||
toIntList : Digest -> List Int | ||
toIntList (Digest data) = | ||
data | ||
{-| Pass a Key and your message in Bytes to compute a Digest | ||
import HmacSha1.Key as Key | ||
import Bytes.Encode | ||
{-| Convert a Digest into a base64 String Result | ||
case toBase64 (digest "key" "message") of | ||
Ok base64String -> | ||
"Base64 string: " ++ base64String | ||
Err err -> | ||
"Failed to convert the digest" | ||
--> Base64 string: IIjfdNXyFGtIFGyvSWU3fp0L46Q= | ||
-} | ||
toBase64 : Digest -> Result String String | ||
toBase64 (Digest data) = | ||
Base64.encode data | ||
|
||
|
||
{-| Convert a Digest into a base16 String Result | ||
case toHex (digest "key" "message") of | ||
Ok base16String -> | ||
"Hex string: " ++ base16String | ||
Err err -> | ||
"Failed to convert the digest" | ||
--> Hex string: 2088DF74D5F2146B48146CAF4965377E9D0BE3A4 | ||
Bytes.Encode.sequence [] | ||
|> Bytes.Encode.encode | ||
|> fromBytes (Key.fromString "") | ||
|> toBase64 | ||
--> "+9sdGxiqbAgyS31ktx+3Y3BpDh0=" | ||
-} | ||
toHex : Digest -> Result String String | ||
toHex (Digest data) = | ||
Base16.encode data | ||
fromBytes : Key -> Bytes -> Digest | ||
fromBytes = | ||
usingEncoder Encode.bytes | ||
|
||
|
||
|
||
-- HMAC-SHA1 | ||
|
||
|
||
hmac : KeyBytes -> MessageBytes -> List Int | ||
hmac (KeyBytes key) (MessageBytes message) = | ||
usingEncoder : (message -> Encoder) -> Key -> message -> Digest | ||
usingEncoder encoder (Key key) message = | ||
let | ||
oKeyPad = | ||
List.map (Bitwise.xor 0x5C) key | ||
List.map (Encode.unsignedInt8 << Bitwise.xor 0x5C) key | ||
|
||
iKeyPad = | ||
List.map (Bitwise.xor 0x36) key | ||
List.map (Encode.unsignedInt8 << Bitwise.xor 0x36) key | ||
in | ||
List.append iKeyPad message | ||
|> sha1 | ||
|> List.append oKeyPad | ||
|> sha1 | ||
|
||
|
||
|
||
-- KEY | ||
|
||
|
||
type KeyBytes | ||
= KeyBytes (List Int) | ||
|
||
|
||
keyToBytes : String -> KeyBytes | ||
keyToBytes key = | ||
KeyBytes (Bytes.fromUTF8 key) | ||
|
||
|
||
normalizeKey : KeyBytes -> KeyBytes | ||
normalizeKey (KeyBytes key) = | ||
case compare blockSize <| List.length key of | ||
EQ -> | ||
KeyBytes key | ||
|
||
GT -> | ||
padEnd key | ||
|> KeyBytes | ||
|
||
LT -> | ||
sha1 key | ||
|> padEnd | ||
|> KeyBytes | ||
|
||
|
||
padEnd : List Int -> List Int | ||
padEnd bytes = | ||
List.append bytes <| | ||
List.repeat (blockSize - List.length bytes) 0 | ||
|
||
[ Encode.sequence iKeyPad, encoder message ] | ||
|> Encode.sequence | ||
|> Encode.encode | ||
|> SHA1.fromBytes | ||
|> SHA1.toBytes | ||
|> Encode.bytes | ||
|> List.singleton | ||
|> (::) (Encode.sequence oKeyPad) | ||
|> Encode.sequence | ||
|> Encode.encode | ||
|> SHA1.fromBytes | ||
|> Digest | ||
|
||
|
||
-- MESSAGE | ||
{-| Convert a Digest into [elm/bytes](https://package.elm-lang.org/packages/elm/bytes/latest/) Bytes. | ||
You can use this to map it to your own representations. I use it to convert it to | ||
Base16 and Base64 string representations. | ||
import Bytes | ||
import HmacSha1.Key as Key | ||
type MessageBytes | ||
= MessageBytes (List Int) | ||
fromString (Key.fromString "key") "message" | ||
|> toBytes | ||
|> Bytes.width | ||
--> 20 | ||
-} | ||
toBytes : Digest -> Bytes | ||
toBytes (Digest data) = | ||
SHA1.toBytes data | ||
|
||
messageToBytes : String -> MessageBytes | ||
messageToBytes message = | ||
MessageBytes (Bytes.fromUTF8 message) | ||
|
||
{-| Convert a Digest into a List of Integers. Each Integer is in the range | ||
0-255, and represents one byte. Can be useful for passing digest on to other | ||
packages that make use of this convention. | ||
import HmacSha1.Key as Key | ||
-- SHA 1 | ||
fromString (Key.fromString "key") "message" | ||
|> toByteValues | ||
--> [32, 136, 223, 116, 213, 242, 20, 107, 72, 20, 108, 175, 73, 101, 55, 126, 157, 11, 227, 164] | ||
-} | ||
toByteValues : Digest -> List Int | ||
toByteValues (Digest data) = | ||
SHA1.toByteValues data | ||
|
||
blockSize : Int | ||
blockSize = | ||
64 | ||
|
||
{-| Convert a Digest into a base64 String | ||
sha1 : List Int -> List Int | ||
sha1 bytes = | ||
bytes | ||
|> SHA1.fromBytes | ||
|> SHA1.toBytes | ||
import HmacSha1.Key as Key | ||
fromString (Key.fromString "key") "message" | ||
|> toBase64 | ||
--> "IIjfdNXyFGtIFGyvSWU3fp0L46Q=" | ||
-} | ||
toBase64 : Digest -> String | ||
toBase64 (Digest data) = | ||
SHA1.toBase64 data | ||
|
||
-- elm/bytes | ||
-- ENCODE | ||
|
||
{-| Convert a Digest into a base16 String | ||
listToBytes : List Int -> Bytes | ||
listToBytes byteList = | ||
Encode.sequence (List.map intEncoder byteList) | ||
|> Encode.encode | ||
import HmacSha1.Key as Key | ||
fromString (Key.fromString "key") "message" | ||
|> toHex | ||
--> "2088df74d5f2146b48146caf4965377e9d0be3a4" | ||
intEncoder : Int -> Encode.Encoder | ||
intEncoder int = | ||
Encode.unsignedInt32 Bytes.BE int | ||
-} | ||
toHex : Digest -> String | ||
toHex (Digest data) = | ||
SHA1.toHex data |
Oops, something went wrong.