Packages
plinth
0.9.3
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.13
0.1.12
0.1.11
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Bindings to Node.js and browser platform APIs
Current section
Files
Jump to
Current section
Files
src/plinth/browser/crypto/subtle.gleam
import gleam/javascript/array.{type Array}
import gleam/javascript/promise.{type Promise}
import gleam/json.{type Json}
import gleam/list
pub type DigestAlgorithm {
SHA1
SHA256
SHA384
SHA512
}
pub fn digest_algorithm_to_string(algorithm) {
case algorithm {
SHA1 -> "SHA-1"
SHA256 -> "SHA-256"
SHA384 -> "SHA-384"
SHA512 -> "SHA-512"
}
}
@external(javascript, "../../../plinth_browser_crypto_subtle_ffi.mjs", "digest")
fn do_digest(
algorithm: String,
data: BitArray,
) -> Promise(Result(BitArray, String))
pub fn digest(algorithm, data) {
do_digest(digest_algorithm_to_string(algorithm), data)
}
pub type CryptoKey
pub type Format {
Raw
Pkcs8
Spki
}
fn format_to_string(format) {
case format {
Raw -> "raw"
Pkcs8 -> "pkcs8"
Spki -> "spki"
}
}
@external(javascript, "../../../plinth_browser_crypto_subtle_ffi.mjs", "exportKey")
fn do_export(
format: String,
key: CryptoKey,
) -> Promise(Result(BitArray, String))
/// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey
pub fn export(key, format) {
do_export(format_to_string(format), key)
}
/// export Jwk is separate because it returns JSON, other formats return array buffer
@external(javascript, "../../../plinth_browser_crypto_subtle_ffi.mjs", "exportJwk")
pub fn export_jwk(key: CryptoKey) -> Promise(Result(Json, String))
@external(javascript, "../../../plinth_browser_crypto_subtle_ffi.mjs", "generateKey")
fn do_generate_key(
algorithm: PublicKeyAlgorithm,
extractable: Bool,
key_usages: Array(String),
) -> Promise(Result(#(CryptoKey, CryptoKey), String))
pub fn generate_key(algorithm, extractable, key_usages) {
let key_usages =
key_usages
|> list.map(key_usage_to_string)
|> array.from_list
do_generate_key(algorithm, extractable, key_usages)
}
pub type PublicKeyAlgorithm {
RsaHashedKeyGenParams(
name: String,
// This should be at least 2048: see for example see SP 800-131A Rev. 2. Some organizations are now recommending that it should be 4096.
modulus_length: Int,
// Unless you have a good reason to use something else, specify 65537 here ([0x01, 0x00, 0x01]).
public_exponent: BitArray,
hash: DigestAlgorithm,
)
EcKeyGenParams(name: String, named_curve: String)
Ed25519GenParams
}
pub type KeyUsage {
Encrypt
Decrypt
Sign
Verify
DeriveKey
DeriveBits
WrapKey
UnwrapKey
}
fn key_usage_to_string(key_usage) {
case key_usage {
Encrypt -> "encrypt"
Decrypt -> "decrypt"
Sign -> "sign"
Verify -> "verify"
DeriveKey -> "deriveKey"
DeriveBits -> "deriveBits"
WrapKey -> "wrapKey"
UnwrapKey -> "unwrapKey"
}
}
@external(javascript, "../../../plinth_browser_crypto_subtle_ffi.mjs", "importKey")
fn do_import_key(
format: String,
key_data: BitArray,
algorithm: Json,
extractable: Bool,
key_usages: Array(String),
) -> Promise(Result(CryptoKey, String))
pub fn import_key(format, key_data, algorithm, extractable, key_usages) {
let algorithm = import_algorithm_to_json(algorithm)
let key_usages =
key_usages
|> list.map(key_usage_to_string)
|> array.from_list
do_import_key(format, key_data, algorithm, extractable, key_usages)
}
@external(javascript, "../../../plinth_browser_crypto_subtle_ffi.mjs", "importJwk")
fn do_import_jwk(
key_data: Json,
algorithm: Json,
extractable: Bool,
key_usages: Array(String),
) -> Promise(Result(CryptoKey, String))
pub fn import_jwk(key_data, algorithm, extractable, key_usages) {
let algorithm = import_algorithm_to_json(algorithm)
let key_usages =
key_usages
|> list.map(key_usage_to_string)
|> array.from_list
do_import_jwk(key_data, algorithm, extractable, key_usages)
}
pub type ImportAlgorithm {
RsaHashedImportParams(name: String, hash: DigestAlgorithm)
EcKeyImportParams(name: String, named_curve: NamedCurve)
HmacImportParams(hash: DigestAlgorithm)
OtherImportParams(name: String)
}
fn import_algorithm_to_json(algorithm_parameters) {
case algorithm_parameters {
RsaHashedImportParams(name, hash) ->
json.object([
#("name", json.string(name)),
#("hash", json.string(digest_algorithm_to_string(hash))),
])
EcKeyImportParams(name, named_curve) ->
json.object([
#("name", json.string(name)),
#("namedCurve", json.string(named_curve_to_string(named_curve))),
])
HmacImportParams(hash) ->
json.object([
#("name", json.string("HMAC")),
#("hash", json.string(digest_algorithm_to_string(hash))),
])
OtherImportParams(name) -> json.object([#("name", json.string(name))])
}
}
pub type NamedCurve {
P256
P384
P521
}
fn named_curve_to_string(named_curve) {
case named_curve {
P256 -> "P-256"
P384 -> "P-384"
P521 -> "P-521"
}
}
@external(javascript, "../../../plinth_browser_crypto_subtle_ffi.mjs", "sign")
fn do_sign(
algorithm: Json,
key: CryptoKey,
data: BitArray,
) -> Promise(Result(BitArray, String))
pub fn sign(algorithm, key, data) {
let algorithm = sign_algorithm_to_json(algorithm)
do_sign(algorithm, key, data)
}
pub type SignAlgorithm {
RsaSsaPkcs1v15
RsaPssParams(salt_length: Int)
EcdsaParams(hash: DigestAlgorithm)
Hmac
Ed25519
}
fn sign_algorithm_to_json(key_algorithm) {
case key_algorithm {
RsaSsaPkcs1v15 -> json.object([#("name", json.string("RSASSA-PKCS1-v1_5"))])
RsaPssParams(salt_length) ->
json.object([
#("name", json.string("RSA-PSS")),
#("saltLength", json.int(salt_length)),
])
EcdsaParams(hash) ->
json.object([
#("name", json.string("ECDSA")),
#("hash", json.string(digest_algorithm_to_string(hash))),
])
Hmac -> json.object([#("name", json.string("HMAC"))])
Ed25519 -> json.object([#("name", json.string("Ed25519"))])
}
}
@external(javascript, "../../../plinth_browser_crypto_subtle_ffi.mjs", "verify")
fn do_verify(
algorithm: Json,
key: CryptoKey,
signature: BitArray,
data: BitArray,
) -> Promise(Result(Bool, String))
pub fn verify(algorithm, key, signature, data) {
let algorithm = sign_algorithm_to_json(algorithm)
do_verify(algorithm, key, signature, data)
}