Skip to content

Hex+aes #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 45 additions & 10 deletions crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@
## Functions
- `md5(string)` - return md5 checksum from string.
- `sha256(string)` - return sha256 checksum from string.
- `aes_encrypt(string, string, string, string)` - return AES encrypted hex-encoded ciphertext
- `aes_decrypt(string, string, string, string)` - return AES decrypted hex-encoded plain text
- `aes_encrypt(string, string, string, string)` - return AES encrypted binary ciphertext
- `aes_decrypt(string, string, string, string)` - return AES decrypted binary text
- `aes_encrypt_hex(string, string, string, string)` - return AES encrypted hex-encoded ciphertext
- `aes_decrypt_hex(string, string, string, string)` - return AES decrypted hex-encoded plain text

AES support 3 modes: GCM, CBC, and CTR - first parameter is mode, second is hex-encoded key, third is hex-encoded initialization vector or nonce - depending on the mode, and forth is hex-encoded plain text or ciphertext.
AES support 3 modes: GCM, CBC, and CTR - first parameter is mode, second is hex-encoded key, third is hex-encoded
initialization vector or nonce - depending on the mode, and forth is hex-encoded plain text or ciphertext.

Since lua strings are binary safe, you can use any binary data as input and output and, for your convenience, the
library also provides hex-encoded versions of the encrypt and decrypt functions. The first argument (the mode string)
can be one of the following: "GCM", "CBC", or "CTR" (case-insensitive) and is not hex-encoded for the hex variants.

## Examples

```lua
local crypto = require("crypto")
local crypto = require 'crypto'

-- md5
if not(crypto.md5("1\n") == "b026324c6904b2a9cb4b88d6d61c81d1") then
Expand All @@ -23,18 +30,46 @@ if not(crypto.sha256("1\n") == "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9
error("sha256")
end

--- aes encrypt in GCM mode
s, err = crypto.aes_encrypt(1, "86e15cbc1cbf510d8f2e51d4b63a2144", "b6b86d581a991a652158bd10", "48656c6c6f20776f726c64")
--- aes encrypt in GCM mode with hex-encoded data
s, err = crypto.aes_encrypt_hex(crypto.GCM, "86e15cbc1cbf510d8f2e51d4b63a2144", "b6b86d581a991a652158bd10", "48656c6c6f20776f726c64")
assert(not err, err)
if not(s == "7ec4e38508a26abf7b46e8dc90a7299d5144bcf045e460c3ef6b3e") then
error("encrypt AES")
end
assert(not err, err)

--- aes decrypt in GCM mode
s, err = crypto.aes_decrypt(1, "86e15cbc1cbf510d8f2e51d4b63a2144", "b6b86d581a991a652158bd10", "7ec4e38508a26abf7b46e8dc90a7299d5144bcf045e460c3ef6b3e")
--- aes decrypt in GCM mode with hex-encoded data
s, err = crypto.aes_decrypt_hex(crypto.GCM, "86e15cbc1cbf510d8f2e51d4b63a2144", "b6b86d581a991a652158bd10", "7ec4e38508a26abf7b46e8dc90a7299d5144bcf045e460c3ef6b3e")
assert(not err, err)
if not(s == "48656c6c6f20776f726c64") then
error("decrypt AES)
error("decrypt AES")
end

--- Binary examples setup of binary strings equivalent to the hex-encoded strings above:
local hex = require 'hex'
local key, iv, plaintext, encrypted, err
key, err = hex.decode_string('86e15cbc1cbf510d8f2e51d4b63a2144')
assert(not err, err)
iv, err = hex.decode_string('b6b86d581a991a652158bd10')
assert(not err, err)
plaintext, err = hex.decode_string('48656c6c6f20776f726c64')
assert(not err, err)
s, err = crypto.aes_encrypt(crypto.GCM, key, iv, plaintext)
assert(not err, err)
encrypted, err = hex.decode_string("7ec4e38508a26abf7b46e8dc90a7299d5144bcf045e460c3ef6b3e")
assert(not err, err)

--- aes encrypt binary in GCM mode
s, err = crypto.aes_encrypt(crypto.GCM, key, iv, plaintext)
assert(not err, err)
if not(s == encrypted) then
error("encrypt AES")
end

--- aes decrypt in GCM mode
s, err = crypto.aes_decrypt(crypto.GCM, key, iv, encrypted)
assert(not err, err)
if not(s == plaintext) then
error("decrypt AES")
end

```
40 changes: 40 additions & 0 deletions crypto/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ func SHA256(L *lua.LState) int {

// AESEncrypt implements AES encryption in Lua.
func AESEncrypt(l *lua.LState) int {
modeStr := l.CheckString(1)
m, err := parseString(modeStr)
if err != nil {
l.ArgError(1, err.Error())
}
key := []byte(l.CheckString(2))
iv := []byte(l.CheckString(3))
data := []byte(l.CheckString(4))
enc, err := encryptAES(m, key, iv, data)
if err != nil {
l.Push(lua.LNil)
l.Push(lua.LString(fmt.Sprintf("failed to encrypt: %v", err)))
return 2
}
l.Push(lua.LString(enc))
return 1
}

// AESEncryptHex implements AES encryption in Lua.
func AESEncryptHex(l *lua.LState) int {
m, key, iv, data, err := decodeParams(l)
if err != nil {
l.Push(lua.LNil)
Expand All @@ -47,6 +67,26 @@ func AESEncrypt(l *lua.LState) int {

// AESDecrypt implement AES decryption in Lua.
func AESDecrypt(l *lua.LState) int {
modeStr := l.CheckString(1)
m, err := parseString(modeStr)
if err != nil {
l.ArgError(1, err.Error())
}
key := []byte(l.CheckString(2))
iv := []byte(l.CheckString(3))
data := []byte(l.CheckString(4))
dec, err := decryptAES(m, key, iv, data)
if err != nil {
l.Push(lua.LNil)
l.Push(lua.LString(fmt.Sprintf("failed to decrypt: %v", err)))
return 2
}
l.Push(lua.LString(dec))
return 1
}

// AESDecryptHex implement AES decryption in Lua.
func AESDecryptHex(l *lua.LState) int {
m, key, iv, data, err := decodeParams(l)
if err != nil {
l.Push(lua.LNil)
Expand Down
10 changes: 9 additions & 1 deletion crypto/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/vadv/gopher-lua-libs/filepath"
"github.com/vadv/gopher-lua-libs/hex"
"github.com/vadv/gopher-lua-libs/ioutil"
"github.com/vadv/gopher-lua-libs/tests"
)

func TestApi(t *testing.T) {
preload := tests.SeveralPreloadFuncs(Preload)
preload := tests.SeveralPreloadFuncs(
Preload,
filepath.Preload,
hex.Preload,
ioutil.Preload,
)
assert.NotZero(t, tests.RunLuaTestFile(t, preload, "./test/test_api.lua"))
}
14 changes: 10 additions & 4 deletions crypto/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ func Preload(L *lua.LState) {
// Loader is the module loader function.
func Loader(L *lua.LState) int {
t := L.NewTable()
// Load the constants
for name := range modeNames {
t.RawSetString(name, lua.LString(name))
}
L.SetFuncs(t, api)
L.Push(t)
return 1
}

var api = map[string]lua.LGFunction{
"md5": MD5,
"sha256": SHA256,
"aes_encrypt": AESEncrypt,
"aes_decrypt": AESDecrypt,
"md5": MD5,
"sha256": SHA256,
"aes_encrypt_hex": AESEncryptHex,
"aes_decrypt_hex": AESDecryptHex,
"aes_encrypt": AESEncrypt,
"aes_decrypt": AESDecrypt,
}
1 change: 1 addition & 0 deletions crypto/test/data/1.data.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello world
1 change: 1 addition & 0 deletions crypto/test/data/1.expected.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�4� �����
1 change: 1 addition & 0 deletions crypto/test/data/1.init.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�¿: ������
1 change: 1 addition & 0 deletions crypto/test/data/1.key.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
��\��Q�.QԶ:!D
Expand Down
Loading