Crypto
Must be included via require
.
Non-Cryptographic Hashing Algorithms
crypto.lua
Hash a string using Lua's version of the DJB2 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
local crypto = require("crypto")
local str = "hello"
assert(crypto.lua(str) == 2871868277)
crypto.md5
Hash a string using the MD5 semi-cryptographic hashing algorithm.
Parameters
- The string to hash.
local crypto = require("crypto")
local str = "hello"
assert(crypto.md5(str) == "5eb63bbbe01eeed093cb22bb8f5acdc3")
crypto.djb2
Hash a string using the DJB2 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
Returns
An integer between 0 and 0xffffffff, inclusive.
local crypto = require("crypto")
local str = "hello"
assert(crypto.djb2(str) == 894552257)
crypto.fnv1
Hash a string using the FNV1 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
local crypto = require("crypto")
local str = "hello"
assert(crypto.fnv1(str) == 9065573210506989167)
crypto.fnv1a
Hash a string using the FNV1A non-cryptographic hashing algorithm.
Parameters
- The string to hash.
local crypto = require("crypto")
local str = "hello"
assert(crypto.fnv1a(str) == 8618312879776256743)
crypto.joaat
Hash a string using the JOAAT non-cryptographic hashing algorithm.
Parameters
- The string to hash.
Returns
An integer between 0 and 0xffffffff, inclusive.
local crypto = require("crypto")
local str = "hello"
assert(crypto.joaat(str) == 1045060183)
crypto.sdbm
Hash a string using the SDBM non-cryptographic hashing algorithm.
Parameters
- The string to hash.
Returns
An integer between 0 and 0xffffffff, inclusive.
local crypto = require("crypto")
local str = "hello"
assert(crypto.sdbm(str) == 430867652)
crypto.crc32
Hash a string using the CRC32 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
- The initial value for the hash. By default, this is zero.
Returns
An integer between 0 and 0xffffffff, inclusive.
local crypto = require("crypto")
local str = "hello"
assert(crypto.crc32(str) == 222957957)
crypto.adler32
Hash a string using the Adler-32 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
- The initial value for the hash. By default, this is zero.
local crypto = require("crypto")
local str = "hello"
assert(crypto.adler32(str) == 103547413)
crypto.lookup3
Hash a string using the Lookup3 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
local crypto = require("crypto")
local str = "hello"
assert(crypto.lookup3(str) == 1252609637)
crypto.times33
Hash a string using the Times33 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
Returns
An integer between 0 and 0xffffffff, inclusive.
local crypto = require("crypto")
local str = "hello"
assert(crypto.times33(str) == 3889643616)
crypto.murmur1
Hash a string using the Murmur1 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
Returns
An integer between 0 and 0xffffffff, inclusive.
local crypto = require("crypto")
local str = "hello"
assert(crypto.murmur1(str) == 3154674178)
crypto.murmur2
Hash a string using the Murmur2 non-cryptographic hashing algorithm.
Parameters
- The string to hash.
Returns
An integer between 0 and 0xffffffff, inclusive.
local crypto = require("crypto")
local str = "hello"
assert(crypto.murmur2(str) == 1151865881)
crypto.murmur2a
Hash a string using the Murmur2A non-cryptographic hashing algorithm.
Parameters
- The string to hash.
Returns
An integer between 0 and 0xffffffff, inclusive.
local crypto = require("crypto")
local str = "hello"
assert(crypto.murmur2a(str) == 2650573207)
crypto.murmur64a
Hash a string using the Murmur64A non-cryptographic hashing algorithm.
Parameters
- The string to hash.
local crypto = require("crypto")
local str = "hello"
assert(crypto.murmur64a(str) == -3190198453633110066)
crypto.murmur64b
Hash a string using the Murmur64A non-cryptographic hashing algorithm.
Parameters
- The string to hash.
local crypto = require("crypto")
local str = "hello"
assert(crypto.murmur64b(str) == 7088720765356542432)
crypto.murmur2neutral
Hash a string using the Murmur2Neutral non-cryptographic hashing algorithm.
Parameters
- The string to hash.
local crypto = require("crypto")
local str = "hello"
assert(crypto.murmur2neutral(str) == 1151865881)
Cryptographic Hashing Algorithms
crypto.sha1
Hash a string using the SHA-1 cryptographic hashing algorithm.
Parameters
- The string to hash.
- When set to true, returns raw binary data. false outputs lowercase hex digits. By default, this is false.
local crypto = require("crypto")
assert(crypto.sha1("Pluto") == "bce8c9aca4120776fad6b517874aa09c46405454")
assert(crypto.sha1("Pluto", true) == "\xbc\xe8\xc9\xac\xa4\x12\x07\x76\xfa\xd6\xb5\x17\x87\x4a\xa0\x9c\x46\x40\x54\x54")
crypto.sha256
Hash a string using the SHA-256 cryptographic hashing algorithm.
Parameters
- The string to hash.
- When set to true, returns raw binary data. false outputs lowercase hex digits. By default, this is false.
local crypto = require("crypto")
assert(crypto.sha256("Pluto") == "8dad5f6a7dd2dcd8c35ec2fd7babb499bcad60d27d73fe73eca2ce025dfd3b47")
assert(crypto.sha256("Pluto", true) == "\x8d\xad\x5f\x6a\x7d\xd2\xdc\xd8\xc3\x5e\xc2\xfd\x7b\xab\xb4\x99\xbc\xad\x60\xd2\x7d\x73\xfe\x73\xec\xa2\xce\x02\x5d\xfd\x3b\x47")
crypto.sha384
Hash a string using the SHA-384 cryptographic hashing algorithm.
Parameters
- The string to hash.
- When set to true, returns raw binary data. false outputs lowercase hex digits. By default, this is false.
local crypto = require("crypto")
assert(crypto.sha384("Pluto", false) == "db890233a919b6745d632633c419e14540ff79f1a89bc4ac194b00e7f913f0f06d5d4d7d6cc2b4aaf9485d223afb8cf0")
crypto.sha512
Hash a string using the SHA-512 cryptographic hashing algorithm.
Parameters
- The string to hash.
- When set to true, returns raw binary data. false outputs lowercase hex digits. By default, this is false.
local crypto = require("crypto")
assert(crypto.sha512("Pluto", false) == "ee8410a8bf9511b94fd6669b5c3e0c4b86e8e4bf7baa8dbd2773d4d6381dd1aecebbe391bef4c6158620ab3f6b794907652d4432c2301d7e1a6caf520565cdf2")
Cryptographic PRNGs
crypto.random
The crypto.random
function uses your operating system's default PRNG.
- On Linux-based systems, this is
/dev/urandom
. - On Windows, this is
BCryptGenRandom
.
This is a cryptographically-secure PRNG when your system can provide those services. However, if it does not, then this is not cryptographically secure. Either way, it provides good randomness.
Parameters
- The minimum value to return.
- The maximum value to return, as a range.
local crypto = require("crypto")
assert(crypto.random(1, 10) < 11)
AES-CBC, AES-CFB
These unauthenticated AES modes take both a key and an IV. The IV must be unique and unpredictable for each encryption session to ensure security.
crypto.encrypt
Parameters
data
— The data to be encrypted.mode
— "aes-cbc-pkcs7" or "aes-cfb-pkcs7" for PKCS#7 padding, or "aes-cbc" or "aes-cfb" if you know what you're doing.key
— Must have a length of 16, 24 or 32 for 128-, 192-, or 256-bit AES, respectively.iv
— Must have a length of 16.
crypto.decrypt
Parameters
data
— The ciphertext to decrypt.mode
— "aes-cbc-pkcs7" or "aes-cfb-pkcs7" for PKCS#7 padding, or "aes-cbc" or "aes-cfb" if you know what you're doing.key
— Must have a length of 16, 24 or 32 for 128-, 192-, or 256-bit AES, respectively.iv
— Must have a length of 16.
Returns the decrypted data on success. Throws an error if the padding was incorrect.
local crypto = require "pluto:crypto"
local key <const> = "A Top Secret Key"
-- Encrypt
local iv = range(16):map(|| -> string.char(math.random(0, 255))):concat("")
local plain = "Hello, world!"
local enc = plain |> crypto.encrypt|"aes-cbc-pkcs7", key, iv|
print(dumpvar(enc))
-- Decrypt
print(crypto.decrypt(enc, "aes-cbc-pkcs7", key, iv)) --> Hello, world!
AES-ECB
This unauthenticated AES mode takes only a key, and is considered to be the weakest. Identical plaintext blocks result in identical ciphertext blocks.
crypto.encrypt
Parameters
data
— The data to be encrypted.mode
— "aes-ecb-pkcs7" for PKCS#7 padding, or "aes-ecb" if you know what you're doing.key
— Must have a length of 16, 24 or 32 for 128-, 192-, or 256-bit AES, respectively.
crypto.decrypt
Parameters
mode
— "aes-ecb-pkcs7" for PKCS#7 padding, or "aes-ecb" if you know what you're doing.data
— The ciphertext to decrypt.key
— Must have a length of 16, 24 or 32 for 128-, 192-, or 256-bit AES, respectively.
Returns the decrypted data on success. Throws an error if the padding was incorrect.
local crypto = require "pluto:crypto"
local key <const> = "A Top Secret Key"
-- Encrypt
local plain = "Hello, world!"
local enc = plain |> crypto.encrypt|"aes-ecb-pkcs7", key|
print(dumpvar(enc)) --> string(16) "`p{����k\21*.>jG"
-- Decrypt
print(crypto.decrypt(enc, "aes-ecb-pkcs7", key)) --> Hello, world!
AES-GCM
This authenticated AES mode allows for additional data that will be validated although not encrypted, such as a Message Authentication Code (MAC).
crypto.encrypt
Parameters
data
— The data to be encrypted.mode
— Must be "aes-gcm". AES-GCM can deal with unpadded data, hence does not need PKCS#7 padding.aadata
— Authenticated data. Will not be encrypted.key
— Must have a length of 16, 24 or 32 for 128-, 192-, or 256-bit AES, respectively.iv
— Must have a length of 16.
Returns two strings: the ciphertext and the authentication tag.
crypto.decrypt
Parameters
data
— The ciphertext to decrypt.mode
— Must be "aes-gcm".aadata
— Authenticated data.key
— Must have a length of 16, 24 or 32 for 128-, 192-, or 256-bit AES, respectively.iv
— Must have a length of 16.tag
— The authentication tag produced by the "encrypt" procedure.
Returns the decrypted data on success. Throws an error if authentication or unpadding failed.
local crypto = require "pluto:crypto"
local key <const> = "A Top Secret Key"
local aadata = "This is Pluto!"
-- Encrypt
local iv = range(16):map(|| -> string.char(math.random(0, 255))):concat("")
local plain = "Hello, world!"
local enc, tag = plain |> crypto.encrypt|"aes-gcm", aadata, key, iv|
print(dumpvar(enc))
print(dumpvar(tag))
-- Decrypt
print(crypto.decrypt(enc, "aes-gcm", aadata, key, iv, tag)) --> Hello, world!
RSA
crypto.generatekeypair
Parameters
mode
— Must be "rsa".bits
— A positive integer for a strict bit-length requirement, or a negative integer for a lax requirement. Common values are1024
,2048
, and4096
.
Returns two tables: The public key (consisting of n
and e
), and the private key (consisting of p
and q
). The Bigint class is used for all values.
local pub, priv = crypto.generatekeypair("rsa", 512)
print(dumpvar(pub))
--> {
--> ["n"] = 11355630182234424425429331560518598643298965915936825610957270519615363349759012613228119611304846673085167794661819394470107090216347491908311079792054357,
--> ["e"] = 65537,
--> }
print(dumpvar(priv))
--> {
--> ["p"] = 115443384115231951475820445136871322101870729500298182134363293112660251666017,
--> ["q"] = 98365361248415863235179644468056200977592391948608651522703704315152579004021,
--> }
crypto.encrypt
Parameters
data
— The data to be encrypted.mode
— "rsa-pkcs1" for PKCS#1 padding, or "rsa" if you know what you're doing.key
— The public or private key to use. Commonly, a public key is used to encrypt data.
crypto.decrypt
Parameters
data
— The ciphertext to decrypt.mode
— "rsa-pkcs1" for PKCS#1 padding, or "rsa" if you know what you're doing.key
— The public or private key to use. If the data was encrypted with the public key, the private key is needed to decrypt it.
local { base64, bigint, crypto } = require "pluto:*"
local priv = {
p = new bigint("115443384115231951475820445136871322101870729500298182134363293112660251666017"),
q = new bigint("98365361248415863235179644468056200977592391948608651522703704315152579004021"),
}
-- Derive public key
local pub = {
n = priv.p * priv.q, -- 11355630182234424425429331560518598643298965915936825610957270519615363349759012613228119611304846673085167794661819394470107090216347491908311079792054357
e = new bigint(0x10001) -- 65537
}
-- Encrypt
local enc = crypto.encrypt("A secret message to the owner of the private key.", "rsa-pkcs1", pub)
print(base64.encode(enc))
-- Decrypt
print(enc |> crypto.decrypt|"rsa-pkcs1", priv|) --> A secret message to the owner of the private key.
crypto.sign
Parameters
data
— The data to sign.mode
— "rsa-sha256" or "rsa-sha1".key
— The private key to use.
crypto.verify
Parameters
data
— The data that was signed.mode
— "rsa-sha256" or "rsa-sha1".key
— The public key corresponding to the signer's private key.signature
— The signature produced by the "sign" procedure.
Returns a boolean that indicates if the signature validated successfully.
local { base64, bigint, crypto } = require "pluto:*"
local priv = {
p = new bigint("115443384115231951475820445136871322101870729500298182134363293112660251666017"),
q = new bigint("98365361248415863235179644468056200977592391948608651522703704315152579004021"),
}
-- Derive public key
local pub = {
n = priv.p * priv.q, -- 11355630182234424425429331560518598643298965915936825610957270519615363349759012613228119611304846673085167794661819394470107090216347491908311079792054357
e = new bigint(0x10001) -- 65537
}
-- Sign
local msg = "The canary has left the nest."
local sig = msg |> crypto.sign|"rsa-sha256", priv|
print(base64.encode(sig)) --> un1g04+cwG8WxYDpSlj4PO/hsTqSITgYKycRuR+m3AE6ypLyUCrVHC/0j4M3DeW81ADZVda6TVkC/Ht8EdYeFw==
-- Verify
print(crypto.verify(msg, "rsa-sha256", pub, sig)) --> true