Skip to content

Commit

Permalink
messagepack support for encrypt/decrypt
Browse files Browse the repository at this point in the history
  • Loading branch information
skinkade committed Sep 14, 2021
1 parent 597dbc5 commit 6714fc2
Show file tree
Hide file tree
Showing 13 changed files with 245 additions and 15 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Change Log
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).

## [0.2.2]
### Added
messagepack support for uniformity.random's encrypt and decrypt

## [0.2.1]
### Added
rand-shuffle function to uniformity.random
Expand All @@ -24,6 +28,7 @@ JVM and ClojureScript support for cryptographically-random:
- collection samples
- passwords/passphrases

[0.2.1]: https://github.com/skinkade/uniformity/compare/v0.2.1...v0.2.2
[0.2.1]: https://github.com/skinkade/uniformity/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/skinkade/uniformity/compare/v0.1.1...v0.2.0
[0.1.1]: https://github.com/skinkade/uniformity/compare/v0.1.0...v0.1.1
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ or `crypto.randomBytes` in Node.js.
and strings with AES-GCM, using passwords and/or keys.
Passwords are treated as UTF-8 strings and processed with 100,000 rounds of
PBKDF2-HMAC-SHA256 by default.

Output can be chosen to be a Clojure map, JSON, or msgpack.
[See documentation](doc/crypto.md).

```clojure
Expand Down Expand Up @@ -58,6 +60,7 @@ PBKDF2-HMAC-SHA256 by default.
- Encoding / decoding Base64 / Hex
- Encoding / decoding UTF-8 strings
- JSON (de)serialization
- msgpack (de)serialization

Input of encoding functions and output of decoding functions are byte arrays
(byte[] on JVM, Uint8Array in JS).
Expand Down
1 change: 1 addition & 0 deletions doc/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Plaintext strings are treated as UTF-8 bytes.

`encrypt` can take two additional flags:
- `:json` makes a compact cryptopack and serializes it to JSON
- `:msgpack` makes a compact cryptopack and serializes it to a msgpack byte array
- `:padded` - while AES-GCM internally pads plaintext to intervals of 16 bytes,
this flag enables pre-emptive padding so that the length of the ciphertext
does not match that of the plaintext
Expand Down
125 changes: 125 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"dependencies": {
"asmcrypto.js": "^2.3.2",
"msgpack5": "^5.3.2",
"shadow-cljs": "^2.15.2"
}
}
5 changes: 3 additions & 2 deletions project.clj
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
(defproject io.github.skinkade/uniformity "0.2.1"
(defproject io.github.skinkade/uniformity "0.2.2"
:description "A Clojure(Script) library for easy-to-use cryptographic primitives and utilities, aiming for uniform behavior between Clojure platform targets"
:url "https://github.com/skinkade/uniformity"
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "https://www.eclipse.org/legal/epl-2.0/"}
:dependencies [[org.clojure/clojure "1.10.1"]
[commons-codec/commons-codec "1.15"]
[org.clojure/data.json "2.4.0"]]
[org.clojure/data.json "2.4.0"]
[clojure-msgpack "1.2.1"]]
:repl-options {:init-ns uniformity.random})
20 changes: 13 additions & 7 deletions src/uniformity/crypto.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
and the ciphertext.
Add `:json` to return a JSON string with compact field names.
Add `:msgpack` to return a msgpack byte array with compact field names.
Add `:padded` to PKCS#7-pad plaintext to nearest 16 bytes to hide
exact plaintext length."
[plaintext
Expand All @@ -64,6 +65,7 @@
(let [flags (set (flatten flags))
padded (:padded flags)
json (:json flags)
msgpack (:msgpack flags)
from-str (string? plaintext)
plaintext (if from-str
(util/str->utf8 plaintext)
Expand All @@ -90,9 +92,12 @@
cryptopack (if (empty? pack-flags)
cryptopack
(assoc cryptopack :flags pack-flags))]
(if json
(proc/cryptopack->json cryptopack)
cryptopack)))
(when (and json msgpack)
(throw (ex-info ":json and :msgpack cannot be used together"
{:bad-flags-args flags})))
(cond json (proc/cryptopack->json cryptopack)
msgpack (proc/cryptopack->msgpack cryptopack)
:default cryptopack)))

(defn decrypt
" Decrypt ciphertext using one of the provided keys.
Expand All @@ -105,13 +110,14 @@
[ciphertext key]
{:pre [(or
(string? ciphertext)
(map? ciphertext))
(map? ciphertext)
(compat-bytes? ciphertext))
(or
(string? key)
(compat-bytes? key))]}
(let [cryptopack (if (string? ciphertext)
(proc/json->cryptopack ciphertext)
ciphertext)
(let [cryptopack (cond (string? ciphertext) (proc/json->cryptopack ciphertext)
(compat-bytes? ciphertext) (proc/msgpack->cryptopack ciphertext)
:default ciphertext)
flags (if (contains? cryptopack :flags)
(set (:flags cryptopack))
#{})
Expand Down
37 changes: 32 additions & 5 deletions src/uniformity/internals/crypto/processing.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
(defonce ^:private cryptopack-fields
(reverse-basic-map cryptopack-compact-fields))

(defn ^:private cryptopack-compact-swap [c target-keys]
(defn cryptopack-compact-swap [c target-keys]
(cond
(map? c) (reduce-kv
(fn [acc k v]
Expand All @@ -52,16 +52,31 @@
(cryptopack-compact-swap v target-keys)))
{} c)
(coll? c) (mapv #(cryptopack-compact-swap % target-keys) c)
(compat-bytes? c) (str "b64:" (util/base64-encode-urlsafe c))
(and (string? c)
(> (compat-count c) 4)
(= "b64:" (subs c 0 4))) (util/base64-decode (subs c 4))
(or (string? c) (keyword? c)) (if
(contains? target-keys c)
(get target-keys c)
c)
:else c))

(defn base64-bytes-swap [obj]
(cond (compat-bytes? obj)
(str "b64:" (util/base64-encode-urlsafe obj))

(and (string? obj)
(> (count obj) 4)
(= "b64:" (subs obj 0 4)))
(util/base64-decode (subs obj 4))

(map? obj)
(reduce-kv (fn [acc k v] (assoc acc k (base64-bytes-swap v)))
{}
obj)

(coll? obj)
(mapv base64-bytes-swap obj)

:default obj))

(defn pkcs7-pad-bytes
[bytes boundary]
(let [bytes (vec bytes)
Expand Down Expand Up @@ -95,12 +110,24 @@
(defn cryptopack->json [cryptopack]
(as-> cryptopack c
(cryptopack-compact-swap c cryptopack-fields)
(base64-bytes-swap c)
(util/json-encode c)
(subs c 1 (dec (compat-count c))))) ; bug: data.json wraps in an array

(defn json->cryptopack [json]
(-> json
(util/json-decode)
(base64-bytes-swap)
(cryptopack-compact-swap cryptopack-compact-fields)))

(defn cryptopack->msgpack [cryptopack]
(-> cryptopack
(cryptopack-compact-swap cryptopack-fields)
util/msgpack-serialize))

(defn msgpack->cryptopack [msgpack]
(-> msgpack
util/msgpack-deserialize
(cryptopack-compact-swap cryptopack-compact-fields)))

(defn key-from-password
Expand Down
10 changes: 9 additions & 1 deletion src/uniformity/internals/util_java.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(ns uniformity.internals.util-java
(:require [clojure.data.json :as json])
(:require [clojure.data.json :as json]
[msgpack.core :as msg]
[msgpack.clojure-extensions])
(:import [org.apache.commons.codec.binary Base64 Hex]))

(defn base64-encode
Expand Down Expand Up @@ -30,6 +32,12 @@
[^String string]
(json/read-str string))

(defn msgpack-serialize ^bytes [obj]
(msg/pack obj))

(defn msgpack-deserialize [^bytes msgpack]
(msg/unpack msgpack))

(defn str->utf8
^bytes [^String string]
(.getBytes string "UTF8"))
Expand Down
14 changes: 14 additions & 0 deletions src/uniformity/internals/util_js.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
[clojure.string :refer [replace]]
[uniformity.internals.validation :refer [compat-count]]))

(def msgpack ((js/require "msgpack5")))

(defn base64-encode
^String [^js/Uint8Array bytes]
(base64/encodeByteArray bytes))
Expand Down Expand Up @@ -56,6 +58,18 @@
(.parse js/JSON)
(js->clj)))

(defn msgpack-serialize
^js/Uint8Array [object]
(->> object
clj->js
(.encode msgpack)))

(defn msgpack-deserialize
[^bytes bytes]
(->> bytes
(.decode msgpack)
js->clj))

;; super hacky!
(defn str->utf8
^js/Uint8Array [^String string]
Expand Down
Loading

0 comments on commit 6714fc2

Please sign in to comment.