Skip to content

Commit

Permalink
v0.3.0: Async and asymmetric encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
skinkade committed Sep 23, 2021
1 parent c49c1a4 commit 28265cd
Show file tree
Hide file tree
Showing 41 changed files with 1,519 additions and 696 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- run: lein test

# ClojureScript
- run: npx shadow-cljs compile test
- run: npx shadow-cljs compile node-test

workflows:
build:
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ pom.xml.asc
/.calva
/.lsp
/.shadow-cljs
/node_modules
/node_modules
/ssl
/.clj-kondo
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# 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.3.0]
### Added
RSA support
Crypto module exposing AES-GCM, RSA, PBKDF2
### Changed
Encryption functionality is now async
Cryptopacks have been moved to their own module
cryptopack/encrypt is now keyword-based for its arguments

## [0.2.2]
### Added
messagepack support for uniformity.random's encrypt and decrypt
Expand Down Expand Up @@ -28,7 +37,8 @@ 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.3.0]: https://github.com/skinkade/uniformity/compare/v0.2.2...v0.3.0
[0.2.2]: 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
41 changes: 15 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,36 @@
[![Clojars Project](https://img.shields.io/clojars/v/io.github.skinkade/uniformity.svg)](https://clojars.org/io.github.skinkade/uniformity)
[![CircleCI](https://circleci.com/gh/skinkade/uniformity/tree/main.svg?style=svg)](https://circleci.com/gh/skinkade/uniformity/?branch=main)

**This library is an unstable work-in-progress and breaking changes are
expected in coming releases.**
**This library a work-in-progress.**

`uniformity` is a Clojure(Script) library for easy-to-use cryptographic primitives
and utilities, aiming for uniform behavior between Clojure platform targets.
The library should function the same whether you're using it on the JVM
or with ClojureScript. CLR and BEAM support planned.
or with ClojureScript. CLR support planned.

On the JVM, `uniformity` is backed by `java.Security.SecureRandom`.
Within ClojureScript, it's backed by either `window.crypto.getRandomValues` in-browser,
or `crypto.randomBytes` in Node.js.
The library is effectively a wrapper for the following:
- JVM: `java.security.SecureRandom` and `javax.crypto`
- Node: built-in crypto module
- Browser: `window.crypto.getRandomValues` and the SubtleCrypto Web API
* Note that SubtleCrypto, and therefore this library, are only usable in HTTPS contexts



## Modules

### Crypto
`uniformity.crypto` provides a high-level, easy-to-use API for encrypting bytes
and strings with AES-GCM, using passwords and/or keys.

`uniformity.crypto.core` provides asynchronous AES-GCM, RSA, and PBKDF2 functionality.
[See documentation](doc/crypto/core.md).

`uniformity.crypto.cryptopack` provides a high-level API for encrypting bytes
and strings with AES-GCM; using passwords, symmetric keys, or RSA 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
;; password
(def password "Strong password")
(def encrypted (encrypt "Secret text" password))

;; key
(def secret-key (rand-bytes 16))
(def encrypted (encrypt "Secret text" secret-key))

;; or both...
(def encrypted (encrypt "Secret text" [password secret-key]))
[See documentation](doc/crypto/cryptopack.md).

;; ... and any key supplied works to decrypt
(decrypt encrypted password)
(decrypt encrypted secret-key)
```

### Random
`uniformity.random` contains functions for crytographically random:
Expand All @@ -67,4 +56,4 @@ Output can be chosen to be a Clojure map, JSON, or msgpack.

Input of encoding functions and output of decoding functions are byte arrays
(byte[] on JVM, Uint8Array in JS).
[See documentation](doc/util.md).
[See documentation](doc/util.md).
5 changes: 2 additions & 3 deletions doc/cljdoc.edn
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{:cljdoc.doc/tree [["Readme" {:file "README.md"}]
["Crypto" {:file "doc/crypto.md"}
["A note on GCM nonces" {:file "doc/crypto/gcm_nonce_note.md"}]
["Low level usage", {:file "doc/crypto/low_level_usage.md"}]]
["Crypto" {:file "doc/crypto/core.md"}
["Cryptopack" {:file "doc/crypto/cryptopack.md"}]]
["Random" {:file "doc/random.md"}]
["Util" {:file "doc/util.md"}]]}
184 changes: 0 additions & 184 deletions doc/crypto.md

This file was deleted.

64 changes: 64 additions & 0 deletions doc/crypto/core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# uniformity.crypto.core

The core cryptography module provides asynchronous primitives for
AES-GCM, RSA, and PBKDF2.
Each function returns a channel containing either the result of the operation,
or and Exception (JVM) or Error (JS).

The AES-GCM encryption function auto-generates a 96-bit random nonce if one is
not provided. For this reason, the return value is a map containing the nonce
and the ciphertext.

```clojure
(def plaintext (byte-array [1 2 3 4]))
(def enc-key (rand-bytes 16))
(def enc-nonce (rand-bytes 12))

;; with nonce provided
(<!! (aes-gcm-encrypt plaintext enc-key :nonce enc-nonce))
;; => {:nonce #object["[B" 0x321111aa "[B@321111aa"],
;; :ciphertext #object["[B" 0x6098f59e "[B@6098f59e"]}

;; auto-generated nonce
(<!! (aes-gcm-encrypt plaintext enc-key))
;; => {:nonce #object["[B" 0x61d1f2ad "[B@61d1f2ad"],
;; :ciphertext #object["[B" 0x222d5723 "[B@222d5723"]}
```

`rsa-generate-keypair` creates a public/private keypair of 2048, 3072,
or 4096 bits.
Public keys are in SPKI format, and private keys are in PKCS#8 format, as bytes.

```clojure
(<!!
(go
(let [plaintext (byte-array [1 2 3 4])
keypair (<? (rsa-generate-keypair 2048))
pubkey (:public keypair)
privkey (:private keypair)
ciphertext (<! (rsa-encrypt plaintext
pubkey))
decrypted (<! (rsa-decrypt ciphertext
privkey))]
(vec decrypted))))
;; => [1 2 3 4]
```

The PBKDF2 function only requires passing a password, and provides sane defaults
for all other parameters.

```clojure
(<!! (pbkdf2 "password"))
;; => {:key #object["[B" 0x78783c2b "[B@78783c2b"],
;; :salt #object["[B" 0x1c59c4af "[B@1c59c4af"],
;; :iterations 100000,
;; :hash :sha256,
;; :key-length 128}

;; equivalent to above
(<!! (pbkdf2 "password"
:salt (rand-bytes 16)
:iterations 100000
:hash :sha256
:key-length 128))
```
Loading

0 comments on commit 28265cd

Please sign in to comment.