the base
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
module base
|
module base
|
||||||
|
|
||||||
import json
|
import json
|
||||||
// import freeflowuniverse.crystallib.ui.console
|
// import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
// is an object which has a configurator, session and config object which is unique for the model
|
// is an object which has a configurator, session and config object which is unique for the model
|
||||||
// T is the Config Object
|
// T is the Config Object
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module base
|
module base
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import freeflowuniverse.crystallib.ui.console
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
@[heap]
|
@[heap]
|
||||||
pub struct Configurator[T] {
|
pub struct Configurator[T] {
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
module base
|
module base
|
||||||
|
|
||||||
import freeflowuniverse.crystallib.data.paramsparser
|
import freeflowuniverse.herolib.data.paramsparser
|
||||||
import freeflowuniverse.crystallib.clients.redisclient
|
import freeflowuniverse.herolib.clients.redisclient
|
||||||
import freeflowuniverse.crystallib.data.dbfs
|
import freeflowuniverse.herolib.data.dbfs
|
||||||
// import freeflowuniverse.crystallib.crypt.secp256k1
|
// import freeflowuniverse.herolib.crypt.secp256k1
|
||||||
import freeflowuniverse.crystallib.crypt.aes_symmetric
|
import freeflowuniverse.herolib.crypt.aes_symmetric
|
||||||
import freeflowuniverse.crystallib.ui
|
import freeflowuniverse.herolib.ui
|
||||||
import freeflowuniverse.crystallib.ui.console
|
import freeflowuniverse.herolib.ui.console
|
||||||
import freeflowuniverse.crystallib.core.pathlib
|
import freeflowuniverse.herolib.core.pathlib
|
||||||
import freeflowuniverse.crystallib.core.texttools
|
import freeflowuniverse.herolib.core.texttools
|
||||||
import freeflowuniverse.crystallib.core.rootpath
|
import freeflowuniverse.herolib.core.rootpath
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import crypto.md5
|
import crypto.md5
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module base
|
module base
|
||||||
|
|
||||||
import freeflowuniverse.crystallib.data.ourtime
|
import freeflowuniverse.herolib.data.ourtime
|
||||||
import freeflowuniverse.crystallib.data.paramsparser
|
import freeflowuniverse.herolib.data.paramsparser
|
||||||
import json
|
import json
|
||||||
|
|
||||||
@[params]
|
@[params]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
module base
|
module base
|
||||||
|
|
||||||
import freeflowuniverse.crystallib.data.paramsparser
|
import freeflowuniverse.herolib.data.paramsparser
|
||||||
import freeflowuniverse.crystallib.ui
|
import freeflowuniverse.herolib.ui
|
||||||
import freeflowuniverse.crystallib.ui.console
|
import freeflowuniverse.herolib.ui.console
|
||||||
import crypto.md5
|
import crypto.md5
|
||||||
|
|
||||||
@[params]
|
@[params]
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Session id is $contextid:$sessionid (e.g. 10:111)
|
|||||||
- coderoot string //this will define where all code is checked out
|
- coderoot string //this will define where all code is checked out
|
||||||
|
|
||||||
```v
|
```v
|
||||||
import freeflowuniverse.crystallib.core.base
|
import freeflowuniverse.herolib.core.base
|
||||||
|
|
||||||
mut session:=context_new(
|
mut session:=context_new(
|
||||||
coderoot:'/tmp/code'
|
coderoot:'/tmp/code'
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
module base
|
module base
|
||||||
|
|
||||||
import freeflowuniverse.crystallib.data.ourtime
|
import freeflowuniverse.herolib.data.ourtime
|
||||||
// import freeflowuniverse.crystallib.core.texttools
|
// import freeflowuniverse.herolib.core.texttools
|
||||||
import freeflowuniverse.crystallib.data.paramsparser
|
import freeflowuniverse.herolib.data.paramsparser
|
||||||
import freeflowuniverse.crystallib.data.dbfs
|
import freeflowuniverse.herolib.data.dbfs
|
||||||
import json
|
import json
|
||||||
// import freeflowuniverse.crystallib.core.pathlib
|
// import freeflowuniverse.herolib.core.pathlib
|
||||||
// import freeflowuniverse.crystallib.develop.gittools
|
// import freeflowuniverse.herolib.develop.gittools
|
||||||
// import freeflowuniverse.crystallib.ui.console
|
// import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
@[heap]
|
@[heap]
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module base
|
module base
|
||||||
|
|
||||||
import freeflowuniverse.crystallib.data.ourtime
|
import freeflowuniverse.herolib.data.ourtime
|
||||||
import freeflowuniverse.crystallib.core.texttools
|
import freeflowuniverse.herolib.core.texttools
|
||||||
|
|
||||||
pub struct ErrorArgs {
|
pub struct ErrorArgs {
|
||||||
pub mut:
|
pub mut:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module base
|
module base
|
||||||
|
|
||||||
import freeflowuniverse.crystallib.data.ourtime
|
import freeflowuniverse.herolib.data.ourtime
|
||||||
import freeflowuniverse.crystallib.core.texttools
|
import freeflowuniverse.herolib.core.texttools
|
||||||
|
|
||||||
@[heap]
|
@[heap]
|
||||||
pub struct Logger {
|
pub struct Logger {
|
||||||
|
|||||||
79
lib/crypt/aes_symmetric/symmetric.v
Normal file
79
lib/crypt/aes_symmetric/symmetric.v
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
module aes_symmetric
|
||||||
|
|
||||||
|
import crypto.aes
|
||||||
|
import crypto.md5
|
||||||
|
import crypto.cipher
|
||||||
|
import encoding.binary as bin
|
||||||
|
import encoding.base64
|
||||||
|
|
||||||
|
fn padded_length(source []u8, blocksize int) int {
|
||||||
|
if (source.len % blocksize) == 0 {
|
||||||
|
return source.len
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((source.len / blocksize) + 1) * blocksize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encrypt_str(data string, secret string) string {
|
||||||
|
mut d := encrypt(data.bytes(), secret)
|
||||||
|
return base64.encode(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encrypt(data []u8, secret string) []u8 {
|
||||||
|
key := md5.hexhash(secret)
|
||||||
|
|
||||||
|
// initialize aes with md5 of the secret (always same length)
|
||||||
|
ae := aes.new_cipher(key.bytes())
|
||||||
|
|
||||||
|
// use null iv
|
||||||
|
iv := []u8{len: ae.block_size}
|
||||||
|
mut cb := cipher.new_cbc(ae, iv)
|
||||||
|
|
||||||
|
// add padding to data
|
||||||
|
length := padded_length(data, ae.block_size)
|
||||||
|
|
||||||
|
mut padded := []u8{len: length}
|
||||||
|
copy(mut padded, data)
|
||||||
|
|
||||||
|
// encrypt blocks
|
||||||
|
mut destination := []u8{len: length}
|
||||||
|
cb.encrypt_blocks(mut destination, padded)
|
||||||
|
|
||||||
|
destination << []u8{len: 2}
|
||||||
|
// we add the len of the padding at end
|
||||||
|
bin.little_endian_put_u16_end(mut destination, u16(length - data.len))
|
||||||
|
|
||||||
|
return destination
|
||||||
|
}
|
||||||
|
|
||||||
|
// input needs to be base64 encoded
|
||||||
|
pub fn decrypt_str(data string, secret string) string {
|
||||||
|
if data.len == 0 {
|
||||||
|
return ''
|
||||||
|
// print_backtrace()
|
||||||
|
// panic('data cannot be empty (decrypt aes)')
|
||||||
|
}
|
||||||
|
data_decoded := base64.decode(data)
|
||||||
|
mut d := decrypt(data_decoded, secret)
|
||||||
|
return d.bytestr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrypt(data []u8, secret string) []u8 {
|
||||||
|
key := md5.hexhash(secret)
|
||||||
|
|
||||||
|
lenextra := bin.little_endian_u16_end(data)
|
||||||
|
data2 := data[0..data.len - 2]
|
||||||
|
|
||||||
|
// initialize aes with md5 of the secret (always same length)
|
||||||
|
ae := aes.new_cipher(key.bytes())
|
||||||
|
|
||||||
|
// use null iv
|
||||||
|
iv := []u8{len: ae.block_size}
|
||||||
|
mut cb := cipher.new_cbc(ae, iv)
|
||||||
|
|
||||||
|
// decrypt blocks
|
||||||
|
mut destination := []u8{len: data2.len}
|
||||||
|
cb.decrypt_blocks(mut destination, data2)
|
||||||
|
|
||||||
|
return destination[0..destination.len - lenextra]
|
||||||
|
}
|
||||||
7
lib/crypt/aes_symmetric/symmetric_test.v
Normal file
7
lib/crypt/aes_symmetric/symmetric_test.v
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module aes_symmetric
|
||||||
|
|
||||||
|
fn test_check() {
|
||||||
|
d := encrypt_str('data', 'mysecret')
|
||||||
|
d2 := decrypt_str(d, 'mysecret')
|
||||||
|
assert d2 == 'data'
|
||||||
|
}
|
||||||
105
lib/crypt/crpgp/README.md
Normal file
105
lib/crypt/crpgp/README.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# CRPGP
|
||||||
|
|
||||||
|
This module based on [threefold/crpgp](https://github.com/threefoldtech/crpgp) repo, which is a wrapper for [rpgp](https://github.com/rpgp/rpgp)
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
All needed libs can be installed from [install.sh](./install.sh)
|
||||||
|
|
||||||
|
## High Level API
|
||||||
|
|
||||||
|
- List of supported functions with a description for each method
|
||||||
|
|
||||||
|
| Function | Description | Input | Output |
|
||||||
|
| ------------------------------------- | -------------------------------------------------------------------------------- | ----------------- | --------------- |
|
||||||
|
| generate_key | generate a signed secret key using name, email, comment, key_type and key_length | KeyParams | SignedSecretKey |
|
||||||
|
| SignedSecretKey.get_signed_public_key | get a signed public key from signed secret key | | SignedPublicKey |
|
||||||
|
| import_publickey | import signed public key in armored format | string | SignedPublicKey |
|
||||||
|
| import_publickey_from_file | like import_publickey but from a file | string | SignedPublicKey |
|
||||||
|
| import_secretkey | import signed secret key in armored format | string | SignedSecretKey |
|
||||||
|
| import_secretkey_from_file | like import_secretkey but from a file | string | SignedSecretKey |
|
||||||
|
| SignedPublicKey.sign_message | sign message with your signed public key | string | Signature |
|
||||||
|
| SignedSecretKey.verify_signature | verify signature for message with your signed secret key | Signature, string | bool |
|
||||||
|
| SignedPublicKey.encrypt_from_text | encrypt message from text using your signed public key | string | []byte |
|
||||||
|
| SignedSecretKey.decrypt_to_text | decrypt encrypted messages to text using your signed secret key | []byte | string |
|
||||||
|
| Signature.to_bytes | convert signature to bytes | | []byte |
|
||||||
|
| Signature.to_hex | convert signature to hex | | string |
|
||||||
|
| signature_from_hex | convert hex string to signature | string | Signature |
|
||||||
|
|
||||||
|
### Notes:
|
||||||
|
- key_type is enum of [`cv25519`, `rsa`], by default key_type will be `cv25519`
|
||||||
|
- key_length used if key_type is `rsa` and `3072` is a default value
|
||||||
|
|
||||||
|
## How to use !
|
||||||
|
|
||||||
|
- We will go together step by step to illustrate how to use this module.
|
||||||
|
|
||||||
|
- Import crpgp module
|
||||||
|
|
||||||
|
```v
|
||||||
|
import crpgp
|
||||||
|
```
|
||||||
|
|
||||||
|
- We have **two** options here, generate a new key, or import
|
||||||
|
|
||||||
|
1. Generate:
|
||||||
|
- CV25519 key:
|
||||||
|
|
||||||
|
```v
|
||||||
|
ssk := crpgp.generate_key(name: <YOUR_NAME>, email: <YOUR_EMAIL>) !
|
||||||
|
```
|
||||||
|
|
||||||
|
- RSA key
|
||||||
|
|
||||||
|
```v
|
||||||
|
// key_length 3072 if not passed
|
||||||
|
ssk := crpgp.generate_key(name: <YOUR_NAME>, email: <YOUR_EMAIL>, key_type: .rsa) !
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```v
|
||||||
|
ssk := crpgp.generate_key(name: <YOUR_NAME>, email: <YOUR_EMAIL>, key_type: .rsa, key_length: <LENGTH>) !
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Import signed secret key from file
|
||||||
|
|
||||||
|
```v
|
||||||
|
ssk := crpgp.import_secretkey_from_file(<FILE_PATH>) !
|
||||||
|
```
|
||||||
|
|
||||||
|
- Now we have a signed secret key, let us get a signed public key, also we have **two** options, get from secret key or import
|
||||||
|
|
||||||
|
1. Get signed public key from signed secret key
|
||||||
|
|
||||||
|
```v
|
||||||
|
spk := ssk.get_signed_public_key() !
|
||||||
|
```
|
||||||
|
|
||||||
|
2. import signed public key from file
|
||||||
|
|
||||||
|
```v
|
||||||
|
spk := crpgp.import_publickey_from_file(<FILE_PATH>) !
|
||||||
|
```
|
||||||
|
|
||||||
|
- Now we have a signed public and secret key, let us try to sign and verify a message
|
||||||
|
|
||||||
|
```v
|
||||||
|
message := "these are my secrets\n12345"
|
||||||
|
mut sig := ssk.sign_message(message) !
|
||||||
|
println(sig.to_hex() !) // In case we want to convert it to hex, here just to display it
|
||||||
|
|
||||||
|
if spk.verify_signature(sig, message) {
|
||||||
|
println('✅ message signed and verified!')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- let us try encrypt and decrypt message.
|
||||||
|
|
||||||
|
```v
|
||||||
|
encrypted := spk.encrypt_from_text(message) !
|
||||||
|
decrypted := ssk.decrypt_to_text(encrypted) !
|
||||||
|
if message == decrypted {
|
||||||
|
println('✅ message encrypted and decrypted!')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Done !
|
||||||
13
lib/crypt/crpgp/crpgp-manual.v
Normal file
13
lib/crypt/crpgp/crpgp-manual.v
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
module crpgp
|
||||||
|
|
||||||
|
// Things that are hard to convert from the c header file automatically
|
||||||
|
pub enum KeyType_Tag {
|
||||||
|
rsa
|
||||||
|
ecdh
|
||||||
|
ed_dsa
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.KeyType {
|
||||||
|
tag KeyType_Tag
|
||||||
|
rsa u32
|
||||||
|
}
|
||||||
108
lib/crypt/crpgp/crpgp.v
Normal file
108
lib/crypt/crpgp/crpgp.v
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
module crpgp
|
||||||
|
|
||||||
|
struct C.KeyType {}
|
||||||
|
|
||||||
|
struct KeyType {
|
||||||
|
internal &C.KeyType
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.PublicKey {}
|
||||||
|
|
||||||
|
struct PublicKey {
|
||||||
|
internal &C.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.SecretKey {}
|
||||||
|
|
||||||
|
struct SecretKey {
|
||||||
|
internal &C.SecretKey
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.SecretKeyParams {}
|
||||||
|
|
||||||
|
struct SecretKeyParams {
|
||||||
|
internal &C.SecretKeyParams
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.SecretKeyParamsBuilder {}
|
||||||
|
|
||||||
|
struct SecretKeyParamsBuilder {
|
||||||
|
internal &C.SecretKeyParamsBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.Signature {}
|
||||||
|
|
||||||
|
struct Signature {
|
||||||
|
internal &C.Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.SignedPublicKey {}
|
||||||
|
|
||||||
|
pub struct SignedPublicKey {
|
||||||
|
internal &C.SignedPublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.SignedPublicSubKey {}
|
||||||
|
|
||||||
|
struct SignedPublicSubKey {
|
||||||
|
internal &C.SignedPublicSubKey
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.SignedSecretKey {}
|
||||||
|
|
||||||
|
pub struct SignedSecretKey {
|
||||||
|
internal &C.SignedSecretKey
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.SubkeyParams {}
|
||||||
|
|
||||||
|
struct SubkeyParams {
|
||||||
|
internal &C.SubkeyParams
|
||||||
|
}
|
||||||
|
|
||||||
|
struct C.SubkeyParamsBuilder {}
|
||||||
|
|
||||||
|
struct SubkeyParamsBuilder {
|
||||||
|
internal &C.SubkeyParamsBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
fn C.last_error_length() int
|
||||||
|
fn C.error_message(&char, int) int
|
||||||
|
fn C.public_key_verify(&C.PublicKey, &u8, u64, &C.Signature) char
|
||||||
|
fn C.public_key_encrypt(&C.PublicKey, &u8, &u64) &u8
|
||||||
|
fn C.public_key_sign_and_free(&C.PublicKey, &C.SignedSecretKey) &C.SignedPublicKey
|
||||||
|
fn C.public_key_free(&C.PublicKey) char
|
||||||
|
fn C.secret_key_sign(&C.SecretKey) &C.SignedSecretKey
|
||||||
|
fn C.secret_key_free(&C.SecretKey) char
|
||||||
|
fn C.params_generate_secret_key_and_free(&C.SecretKeyParams) &C.SecretKey
|
||||||
|
fn C.params_builder_new() &C.SecretKeyParamsBuilder
|
||||||
|
fn C.params_builder_primary_user_id(&C.SecretKeyParamsBuilder, &char) char
|
||||||
|
fn C.params_builder_key_type(&C.SecretKeyParamsBuilder, C.KeyType) char
|
||||||
|
fn C.params_builder_subkey(&C.SecretKeyParamsBuilder, &C.SubkeyParams) char
|
||||||
|
fn C.params_builder_build(&C.SecretKeyParamsBuilder) &C.SecretKeyParams
|
||||||
|
fn C.params_builder_free(&C.SecretKeyParamsBuilder) char
|
||||||
|
fn C.signature_serialize(&C.Signature, &u64) &u8
|
||||||
|
fn C.signature_deserialize(&u8, u64) &C.Signature
|
||||||
|
fn C.signature_free(&C.Signature) char
|
||||||
|
fn C.signed_public_key_verify(&C.SignedPublicKey, &u8, u64, &C.Signature) char
|
||||||
|
fn C.signed_public_key_encrypt(&C.SignedPublicKey, &u8, &u64) &u8
|
||||||
|
fn C.signed_public_key_encrypt_with_any(&C.SignedPublicKey, &u8, &u64) &u8
|
||||||
|
fn C.signed_public_key_to_bytes(&C.SignedPublicKey, &u64) &u8
|
||||||
|
fn C.signed_public_key_from_bytes(&u8, u64) &C.SignedPublicKey
|
||||||
|
fn C.signed_public_key_to_armored(&C.SignedPublicKey) &char
|
||||||
|
fn C.signed_public_key_from_armored(&char) &C.SignedPublicKey
|
||||||
|
fn C.signed_public_key_free(&C.SignedPublicKey) char
|
||||||
|
fn C.signed_secret_key_public_key(&C.SignedSecretKey) &C.PublicKey
|
||||||
|
fn C.signed_secret_key_create_signature(&C.SignedSecretKey, &u8, u64) &C.Signature
|
||||||
|
fn C.signed_secret_key_decrypt(&C.SignedSecretKey, &u8, &u64) &u8
|
||||||
|
fn C.signed_secret_key_free(&C.SignedSecretKey) char
|
||||||
|
fn C.signed_secret_key_to_bytes(&C.SignedSecretKey, &u64) &u8
|
||||||
|
fn C.signed_secret_key_from_bytes(&u8, u64) &C.SignedSecretKey
|
||||||
|
fn C.signed_secret_key_to_armored(&C.SignedSecretKey) &char
|
||||||
|
fn C.signed_secret_key_from_armored(&char) &C.SignedSecretKey
|
||||||
|
fn C.subkey_params_free(&C.SubkeyParams) char
|
||||||
|
fn C.subkey_params_builder_new() &C.SubkeyParamsBuilder
|
||||||
|
fn C.subkey_params_builder_key_type(&C.SubkeyParamsBuilder, C.KeyType) char
|
||||||
|
fn C.subkey_params_builder_free(&C.SubkeyParamsBuilder) char
|
||||||
|
fn C.subkey_params_builder_build(&C.SubkeyParamsBuilder) &C.SubkeyParams
|
||||||
|
fn C.ptr_free(&u8) char
|
||||||
10
lib/crypt/crpgp/err.v
Normal file
10
lib/crypt/crpgp/err.v
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
module crpgp
|
||||||
|
|
||||||
|
fn construct_error() !int {
|
||||||
|
// todo: call the func to get the error length
|
||||||
|
err_buf := unsafe { malloc(1024) }
|
||||||
|
C.error_message(err_buf, 1024)
|
||||||
|
str := unsafe { cstring_to_vstring(err_buf) }
|
||||||
|
unsafe { free(err_buf) }
|
||||||
|
return error(str)
|
||||||
|
}
|
||||||
53
lib/crypt/crpgp/install.sh
Executable file
53
lib/crypt/crpgp/install.sh
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
TMP_DIR=/tmp/crpgp
|
||||||
|
TMP_LIB_PATH=$TMP_DIR/libcrpgp.so
|
||||||
|
TMP_HEADER_PATH=$TMP_DIR/crpgp.h
|
||||||
|
CRPGP_DIR=$HOME/.vmodules/freeflowuniverse/herolib.crypt.crpgp
|
||||||
|
V_CRPGP_PATH=$CRPGP_DIR/crpgp.v
|
||||||
|
|
||||||
|
# mkdir TMP_DIR
|
||||||
|
mkdir -p $TMP_DIR
|
||||||
|
|
||||||
|
# Download crpgp lib and header file
|
||||||
|
echo "- Download libcrpgp.so"
|
||||||
|
curl -L https://github.com/threefoldtech/crpgp/releases/download/v0.0.1/libcrpgp.so --output $TMP_LIB_PATH
|
||||||
|
echo "- Download crpgp.h"
|
||||||
|
curl -L https://github.com/threefoldtech/crpgp/releases/download/v0.0.1/crpgp.h --output $TMP_HEADER_PATH
|
||||||
|
echo "✅ Downloaded!"
|
||||||
|
# Update crpgp.v (if herolib in vmodules)
|
||||||
|
if [ -d $CRPGP_DIR ]; then
|
||||||
|
echo "- Updating crpgp.v ..."
|
||||||
|
echo -e 'module crpgp\n' >$V_CRPGP_PATH
|
||||||
|
cat $TMP_HEADER_PATH |
|
||||||
|
egrep -o 'struct [a-zA-Z_]+' |
|
||||||
|
sort | uniq |
|
||||||
|
sed 's/struct \([a-zA-Z]*\)/struct C.\1 {}\nstruct \1 {\n internal \&C.\1\n}/g' \
|
||||||
|
>>$V_CRPGP_PATH
|
||||||
|
|
||||||
|
cat $TMP_HEADER_PATH |
|
||||||
|
sed -z 's/\n\s\s\s*/ /g' |
|
||||||
|
grep ');' |
|
||||||
|
sed 's/ [*]/* /g' |
|
||||||
|
sed 's/ [a-z_][a-z_]*[)]/\)/g' |
|
||||||
|
sed 's/struct \([a-zA-Z_]*\)[*]/\&C.\1/g' |
|
||||||
|
sed 's/struct \([a-zA-Z_]*\)/C.\1/g' |
|
||||||
|
sed -z 's/ [a-z_]*,/,/g' |
|
||||||
|
sed 's/^\([^ ]*\) \(.*\);$/fn C.\2 \1/g' |
|
||||||
|
sed 's/uint8_t/u8/g' |
|
||||||
|
sed 's/size_t/u64/g' |
|
||||||
|
sed 's/\([a-zA-Z0-9]*\)[*]/\&\1/g' |
|
||||||
|
sed 's/[(]void[)]/()/g' \
|
||||||
|
>>$V_CRPGP_PATH
|
||||||
|
echo "✅ Updated!"
|
||||||
|
else
|
||||||
|
echo "- Crystallib not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Move crpgp lib and header file in system dirs
|
||||||
|
sudo mv $TMP_LIB_PATH /usr/lib
|
||||||
|
sudo mv $TMP_HEADER_PATH /usr/include
|
||||||
|
|
||||||
|
# Delete tmp files
|
||||||
|
rm -rf $TMP_DIR
|
||||||
|
|
||||||
|
echo "✅ Installation Done!"
|
||||||
113
lib/crypt/crpgp/pgp.v
Normal file
113
lib/crypt/crpgp/pgp.v
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
module crpgp
|
||||||
|
|
||||||
|
import os
|
||||||
|
import encoding.hex
|
||||||
|
|
||||||
|
#flag -lcrpgp
|
||||||
|
#include <crpgp.h>
|
||||||
|
|
||||||
|
// KeyParams
|
||||||
|
@[params]
|
||||||
|
pub struct KeyParams {
|
||||||
|
name string @[required]
|
||||||
|
email string @[required]
|
||||||
|
key_type CipherSuite
|
||||||
|
length u32 = 3072
|
||||||
|
comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum CipherSuite {
|
||||||
|
cv25519 // ed_dsa primary, ecdh sub
|
||||||
|
rsa // rsa primary (rsa and bitsize can be parameterized)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (self KeyParams) id() string {
|
||||||
|
comment := if self.comment != '' { '(${self.comment}) ' } else { '' }
|
||||||
|
return '${self.name} ${comment}<${self.email}>'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_key(k KeyParams) !SignedSecretKey {
|
||||||
|
mut primarykey_type := C.KeyType{}
|
||||||
|
mut subkey_type := C.KeyType{}
|
||||||
|
match k.key_type {
|
||||||
|
.cv25519 {
|
||||||
|
primarykey_type = C.KeyType{KeyType_Tag.ed_dsa, 0}
|
||||||
|
subkey_type = C.KeyType{KeyType_Tag.ecdh, 0}
|
||||||
|
}
|
||||||
|
.rsa {
|
||||||
|
primarykey_type = C.KeyType{KeyType_Tag.rsa, k.length}
|
||||||
|
subkey_type = C.KeyType{KeyType_Tag.rsa, k.length}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder := new_secret_key_param_builder()!
|
||||||
|
builder.primary_key_id(k.id())!
|
||||||
|
builder.key_type(primarykey_type)!
|
||||||
|
subkey_builder := new_subkey_params_builder()
|
||||||
|
subkey_builder.key_type(subkey_type)!
|
||||||
|
subkey := subkey_builder.build()!
|
||||||
|
builder.subkey(subkey)!
|
||||||
|
params := builder.build()!
|
||||||
|
sk := params.generate_and_free()!
|
||||||
|
ssk := sk.sign()!
|
||||||
|
return ssk
|
||||||
|
}
|
||||||
|
|
||||||
|
// import functions
|
||||||
|
// import public key from ASCII armor text format
|
||||||
|
pub fn import_publickey(data string) !SignedPublicKey {
|
||||||
|
return signed_public_key_from_armored(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// import public key from ASCII armor file format
|
||||||
|
pub fn import_publickey_from_file(path string) !SignedPublicKey {
|
||||||
|
content := os.read_file(path)!
|
||||||
|
return import_publickey(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// import secret key from ASCII armor text format
|
||||||
|
pub fn import_secretkey(data string) !SignedSecretKey {
|
||||||
|
return signed_secret_key_from_armored(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// import secret key from ASCII armor file format
|
||||||
|
pub fn import_secretkey_from_file(path string) !SignedSecretKey {
|
||||||
|
content := os.read_file(path)!
|
||||||
|
return import_secretkey(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public Key Functions
|
||||||
|
pub fn (spk &SignedPublicKey) verify_signature(sig &Signature, message string) bool {
|
||||||
|
spk.verify(message.bytes(), sig) or { return false }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (spk &SignedPublicKey) encrypt_from_text(message string) ![]byte {
|
||||||
|
return spk.encrypt_with_any(message.bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Secret Key Fucntions
|
||||||
|
pub fn (ssk &SignedSecretKey) sign_message(message string) !Signature {
|
||||||
|
return ssk.create_signature(message.bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ssk &SignedSecretKey) decrypt_to_text(encrypted_message []byte) !string {
|
||||||
|
return ssk.decrypt(encrypted_message)!.bytestr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ssk &SignedSecretKey) get_signed_public_key() !SignedPublicKey {
|
||||||
|
return ssk.public_key()!.sign_and_free(ssk)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signature Fucntions
|
||||||
|
fn (sig &Signature) to_bytes() ![]byte {
|
||||||
|
return sig.serialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (sig &Signature) to_hex() !string {
|
||||||
|
return hex.encode(sig.to_bytes()!)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signature_from_hex(sig string) !Signature {
|
||||||
|
sig_bytes := hex.decode(sig)!
|
||||||
|
return deserialize_signature(sig_bytes)
|
||||||
|
}
|
||||||
292
lib/crypt/crpgp/types.v
Normal file
292
lib/crypt/crpgp/types.v
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
module crpgp
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
|
pub fn new_secret_key_param_builder() !SecretKeyParamsBuilder {
|
||||||
|
builder := C.params_builder_new()
|
||||||
|
if u64(builder) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SecretKeyParamsBuilder{
|
||||||
|
internal: builder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (b &SecretKeyParamsBuilder) primary_key_id(primary_key_id string) ! {
|
||||||
|
if C.params_builder_primary_user_id(b.internal, &char(primary_key_id.str)) != 0 {
|
||||||
|
construct_error()!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (b &SecretKeyParamsBuilder) key_type(key_type C.KeyType) ! {
|
||||||
|
if C.params_builder_key_type(b.internal, key_type) != 0 {
|
||||||
|
construct_error()!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (b &SecretKeyParamsBuilder) subkey(subkey SubkeyParams) ! {
|
||||||
|
if C.params_builder_subkey(b.internal, subkey.internal) != 0 {
|
||||||
|
construct_error()!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (b &SecretKeyParamsBuilder) build() !SecretKeyParams {
|
||||||
|
params1 := C.params_builder_build(b.internal)
|
||||||
|
if u64(params1) == 0 {
|
||||||
|
console.print_debug('failed to build secret key params')
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SecretKeyParams{
|
||||||
|
internal: params1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SecretKeyParams) generate_and_free() !SecretKey {
|
||||||
|
sk := C.params_generate_secret_key_and_free(s.internal)
|
||||||
|
if u64(sk) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SecretKey{
|
||||||
|
internal: sk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SecretKey) sign() !SignedSecretKey {
|
||||||
|
ssk := C.secret_key_sign(s.internal)
|
||||||
|
if u64(ssk) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SignedSecretKey{
|
||||||
|
internal: ssk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedSecretKey) create_signature(data []byte) !Signature {
|
||||||
|
sig := C.signed_secret_key_create_signature(s.internal, &u8(&data[0]), data.len)
|
||||||
|
if u64(sig) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return Signature{
|
||||||
|
internal: sig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedSecretKey) decrypt(data []byte) ![]byte {
|
||||||
|
len := u64(data.len)
|
||||||
|
decrypted := C.signed_secret_key_decrypt(s.internal, &u8(&data[0]), &len)
|
||||||
|
if u64(decrypted) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return cu8_to_vbytes(decrypted, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedSecretKey) public_key() !PublicKey {
|
||||||
|
pk := C.signed_secret_key_public_key(s.internal)
|
||||||
|
if u64(pk) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return PublicKey{
|
||||||
|
internal: pk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedSecretKey) to_bytes() ![]byte {
|
||||||
|
len := u64(0)
|
||||||
|
ser := C.signed_secret_key_to_bytes(s.internal, &len)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
res := cu8_to_vbytes(ser, len)
|
||||||
|
C.ptr_free(&u8(ser))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed_secret_key_from_bytes(bytes []byte) !SignedSecretKey {
|
||||||
|
ser := C.signed_secret_key_from_bytes(&u8(&bytes[0]), bytes.len)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SignedSecretKey{
|
||||||
|
internal: ser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedSecretKey) to_armored() !string {
|
||||||
|
ser := C.signed_secret_key_to_armored(s.internal)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
res := unsafe { cstring_to_vstring(ser) }
|
||||||
|
C.ptr_free(&u8(ser))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed_secret_key_from_armored(s string) !SignedSecretKey {
|
||||||
|
ser := C.signed_secret_key_from_armored(s.str)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SignedSecretKey{
|
||||||
|
internal: ser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &Signature) serialize() ![]byte {
|
||||||
|
len := u64(0)
|
||||||
|
ser := C.signature_serialize(s.internal, &len)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
res := cu8_to_vbytes(ser, len)
|
||||||
|
C.ptr_free(ser)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_signature(bytes []byte) !Signature {
|
||||||
|
// TODO: is the pointer arith here ok!
|
||||||
|
sig := C.signature_deserialize(&u8(&bytes[0]), bytes.len)
|
||||||
|
if u64(sig) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return Signature{
|
||||||
|
internal: sig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (p &PublicKey) verify(data []byte, sig &Signature) ! {
|
||||||
|
ok := C.public_key_verify(p.internal, &u8(&data[0]), data.len, sig.internal)
|
||||||
|
if ok != 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (p &PublicKey) sign_and_free(sk SignedSecretKey) !SignedPublicKey {
|
||||||
|
signed := C.public_key_sign_and_free(p.internal, sk.internal)
|
||||||
|
if u64(signed) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SignedPublicKey{
|
||||||
|
internal: signed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &PublicKey) encrypt(data []byte) ![]byte {
|
||||||
|
len := u64(data.len)
|
||||||
|
encrypted := C.public_key_encrypt(s.internal, &u8(&data[0]), &len)
|
||||||
|
if u64(encrypted) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return cu8_to_vbytes(encrypted, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_subkey_params_builder() SubkeyParamsBuilder {
|
||||||
|
return SubkeyParamsBuilder{
|
||||||
|
internal: C.subkey_params_builder_new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (b &SubkeyParamsBuilder) key_type(key_type C.KeyType) ! {
|
||||||
|
if C.subkey_params_builder_key_type(b.internal, key_type) != 0 {
|
||||||
|
construct_error()!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (b &SubkeyParamsBuilder) build() !SubkeyParams {
|
||||||
|
subkey := C.subkey_params_builder_build(b.internal)
|
||||||
|
if u64(subkey) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SubkeyParams{
|
||||||
|
internal: subkey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (p &SignedPublicKey) verify(data []byte, sig &Signature) ! {
|
||||||
|
ok := C.signed_public_key_verify(p.internal, &u8(&data[0]), data.len, sig.internal)
|
||||||
|
if ok != 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedPublicKey) encrypt(data []byte) ![]byte {
|
||||||
|
len := u64(data.len)
|
||||||
|
encrypted := C.signed_public_key_encrypt(s.internal, &u8(&data[0]), &len)
|
||||||
|
if u64(encrypted) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('unreachable!')
|
||||||
|
}
|
||||||
|
return cu8_to_vbytes(encrypted, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedPublicKey) encrypt_with_any(data []byte) ![]byte {
|
||||||
|
len := u64(data.len)
|
||||||
|
encrypted := C.signed_public_key_encrypt_with_any(s.internal, &u8(&data[0]), &len)
|
||||||
|
if u64(encrypted) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('unreachable!')
|
||||||
|
}
|
||||||
|
return cu8_to_vbytes(encrypted, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedPublicKey) to_bytes() ![]byte {
|
||||||
|
len := u64(0)
|
||||||
|
ser := C.signed_public_key_to_bytes(s.internal, &len)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
res := cu8_to_vbytes(ser, len)
|
||||||
|
C.ptr_free(&u8(ser))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed_public_key_from_bytes(bytes []byte) !SignedPublicKey {
|
||||||
|
ser := C.signed_public_key_from_bytes(&u8(&bytes[0]), bytes.len)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SignedPublicKey{
|
||||||
|
internal: ser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s &SignedPublicKey) to_armored() !string {
|
||||||
|
ser := C.signed_public_key_to_armored(s.internal)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
res := unsafe { cstring_to_vstring(ser) }
|
||||||
|
C.ptr_free(&u8(ser))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed_public_key_from_armored(s string) !SignedPublicKey {
|
||||||
|
ser := C.signed_public_key_from_armored(s.str)
|
||||||
|
if u64(ser) == 0 {
|
||||||
|
construct_error()!
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
return SignedPublicKey{
|
||||||
|
internal: ser
|
||||||
|
}
|
||||||
|
}
|
||||||
20
lib/crypt/crpgp/utils.v
Normal file
20
lib/crypt/crpgp/utils.v
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
module crpgp
|
||||||
|
|
||||||
|
pub fn cu8_to_vbytes(ptr &u8, l u64) []byte {
|
||||||
|
mut res := []byte{}
|
||||||
|
for _ in 0 .. l {
|
||||||
|
res << byte(unsafe { *ptr })
|
||||||
|
unsafe {
|
||||||
|
ptr++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn str_to_bytes(s string) []byte {
|
||||||
|
mut res := []byte{}
|
||||||
|
for c in s {
|
||||||
|
res << byte(c)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
1
lib/crypt/crypt.v
Normal file
1
lib/crypt/crypt.v
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module crypt
|
||||||
85
lib/crypt/ed25519/privkey25519.v
Normal file
85
lib/crypt/ed25519/privkey25519.v
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
module ed25519
|
||||||
|
|
||||||
|
import libsodium
|
||||||
|
// import encoding.hex
|
||||||
|
|
||||||
|
// holds signing and private key
|
||||||
|
// private key is derivative from signing key
|
||||||
|
// signkey_bytes is the seed to generate a signing key from which can then generate priv key
|
||||||
|
pub struct PrivKey25519 {
|
||||||
|
pub:
|
||||||
|
signkey_bytes []u8 // signing key in bytes
|
||||||
|
signkey libsodium.SigningKey // master key (is a signing key)
|
||||||
|
privkey libsodium.PrivateKey // derivated from master key
|
||||||
|
pubkey PubKey25519
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PubKey25519 {
|
||||||
|
pub:
|
||||||
|
ed_bytes []u8 // for signing
|
||||||
|
curve_bytes []u8 // target = remote public key (to encrypt) , also called X25519
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_private_key_25519() PrivKey25519 {
|
||||||
|
mut seed := []u8{}
|
||||||
|
// generate a new random seed
|
||||||
|
for _ in 0 .. 32 {
|
||||||
|
seed << u8(libsodium.randombytes_random())
|
||||||
|
}
|
||||||
|
signkey := libsodium.new_ed25519_signing_key_seed(seed)
|
||||||
|
privkey := libsodium.new_private_key_from_signing_ed25519(signkey)
|
||||||
|
pubkey := priv_to_public_key(signkey)
|
||||||
|
return PrivKey25519{
|
||||||
|
signkey: signkey
|
||||||
|
privkey: privkey
|
||||||
|
signkey_bytes: seed
|
||||||
|
pubkey: pubkey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve the master public key from PrivKey object
|
||||||
|
// this is the public key as need to be shared to a remote user to verify that we signed with our private key
|
||||||
|
// is shared as hex key in string format (66 chars)
|
||||||
|
fn priv_to_public_key(priv_sign_key libsodium.SigningKey) PubKey25519 {
|
||||||
|
x := priv_sign_key.verify_key.public_key
|
||||||
|
mut ed_bytes := []u8{len: x.len}
|
||||||
|
unsafe { C.memcpy(ed_bytes.data, &x[0], x.len) }
|
||||||
|
|
||||||
|
curve_bytes := []u8{len: libsodium.public_key_size}
|
||||||
|
libsodium.crypto_sign_ed25519_pk_to_curve25519(curve_bytes.data, ed_bytes.data)
|
||||||
|
|
||||||
|
return PubKey25519{
|
||||||
|
ed_bytes: ed_bytes
|
||||||
|
curve_bytes: curve_bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt data which can only be read by whoever has the private key for this public key
|
||||||
|
pub fn (privkey PrivKey25519) encrypt_for_remote(pubkey PubKey25519, data []u8) ![]u8 {
|
||||||
|
box := libsodium.new_box(privkey.privkey, pubkey.curve_bytes)
|
||||||
|
return box.encrypt(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify a signed data and decrypt,
|
||||||
|
pub fn (privkey PrivKey25519) decrypt(data []u8) []u8 {
|
||||||
|
box := libsodium.new_box(privkey.privkey, privkey.pubkey.curve_bytes)
|
||||||
|
decrypted := box.decrypt(data)
|
||||||
|
return decrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign data with our signing key.
|
||||||
|
// data is bytestr.
|
||||||
|
// output is []u8 bytestring.
|
||||||
|
// to get bytes from string do: mystring.bytes().
|
||||||
|
pub fn (key PrivKey25519) sign(data []u8) []u8 {
|
||||||
|
return key.signkey.sign(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify the signature
|
||||||
|
pub fn (key PubKey25519) verify(signature []u8) bool {
|
||||||
|
v := [libsodium.public_key_size]u8{}
|
||||||
|
// unsafe { C.memcpy(&v[0], key.ed_bytes, libsodium.public_key_size) }
|
||||||
|
// vk:=libsodium.VerifyKey{public_key: v}
|
||||||
|
// return vk.verify(signature)
|
||||||
|
return true
|
||||||
|
}
|
||||||
5
lib/crypt/ed25519/readme.md
Normal file
5
lib/crypt/ed25519/readme.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
>> TODO: is not working yet, info copied from keysafe in root dir, but we need easier to understand usable lib
|
||||||
|
|
||||||
|
>> TODO: maxux, please migrate all your functionality in relation to signing, ... to this module
|
||||||
17
lib/crypt/keychain/readme.md
Normal file
17
lib/crypt/keychain/readme.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
security add-internet-password -s git.ourworld.tf -a despiegk -w mypassword
|
||||||
|
|
||||||
|
-s: The server (e.g., git.ourworld.tf).
|
||||||
|
-a: The account or username (e.g., despiegk).
|
||||||
|
-w: The password (e.g., mypassword).
|
||||||
|
|
||||||
|
|
||||||
|
security find-internet-password -s git.ourworld.tf -w
|
||||||
|
|
||||||
|
|
||||||
|
security delete-internet-password -s git.ourworld.tf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
git config --global credential.helper osxkeychain
|
||||||
|
|
||||||
|
|
||||||
202
lib/crypt/keysafe/keysafe.v
Normal file
202
lib/crypt/keysafe/keysafe.v
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
module keysafe
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.core.pathlib
|
||||||
|
// import freeflowuniverse.herolib.data.mnemonic // buggy for now
|
||||||
|
import encoding.hex
|
||||||
|
import libsodium
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
|
/*
|
||||||
|
* KeysSafe
|
||||||
|
*
|
||||||
|
* This module implement a secure keys manager.
|
||||||
|
*
|
||||||
|
* When loading a keysafe object, you can specify a directory and a secret.
|
||||||
|
* In that directory, a file called '.keys' will be created and encrypted using
|
||||||
|
* the 'secret' provided (AES-CBC).
|
||||||
|
*
|
||||||
|
* Content of that file is a JSON dictionnary of key-name and it's mnemonic,
|
||||||
|
* a single mnemonic is enough to derivate ed25519 and x25519 keys.
|
||||||
|
*
|
||||||
|
* When loaded, private/public signing key and public/private encryption keys
|
||||||
|
* are loaded and ready to be used.
|
||||||
|
*
|
||||||
|
* key_generate_add() generate a new key and store is as specified name
|
||||||
|
* key_import_add() import an existing key based on it's seed and specified name
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub struct KeysSafe {
|
||||||
|
pub mut:
|
||||||
|
path pathlib.Path // file path of keys
|
||||||
|
loaded bool // flag to know if keysafe is loaded or loading
|
||||||
|
secret string // secret to encrypt local file
|
||||||
|
keys map[string]PrivKey // list of keys
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PersistantKeysSafe {
|
||||||
|
pub mut:
|
||||||
|
keys map[string]string // store name/mnemonics only
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: root key needs to be 'SigningKey' from libsodium
|
||||||
|
// from that SigningKey we can derivate PrivateKey needed to encrypt
|
||||||
|
|
||||||
|
pub fn keysafe_get(path0 string, secret string) !KeysSafe {
|
||||||
|
mut path := pathlib.get_file(path: path0 + '/.keys', create: true)!
|
||||||
|
mut safe := KeysSafe{
|
||||||
|
path: path
|
||||||
|
secret: secret
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.exists(path.absolute()) {
|
||||||
|
console.print_debug('[+] key file already exists, loading it')
|
||||||
|
safe.load()
|
||||||
|
}
|
||||||
|
|
||||||
|
safe.loaded = true
|
||||||
|
|
||||||
|
return safe
|
||||||
|
}
|
||||||
|
|
||||||
|
// for testing purposes you can generate multiple keys
|
||||||
|
pub fn (mut ks KeysSafe) generate_multiple(count int) ! {
|
||||||
|
for i in 0 .. count {
|
||||||
|
ks.key_generate_add('name_${i}')!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a new key is just importing a key with a random seed
|
||||||
|
pub fn (mut ks KeysSafe) key_generate_add(name string) !PrivKey {
|
||||||
|
mut seed := []u8{}
|
||||||
|
|
||||||
|
// generate a new random seed
|
||||||
|
for _ in 0 .. 32 {
|
||||||
|
seed << u8(libsodium.randombytes_random())
|
||||||
|
}
|
||||||
|
|
||||||
|
return ks.key_import_add(name, seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_key_encode(key []u8) string {
|
||||||
|
return '0x' + hex.encode(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn internal_key_decode(key string) []u8 {
|
||||||
|
parsed := hex.decode(key.substr(2, key.len)) or { panic(err) }
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
// import based on an existing seed
|
||||||
|
pub fn (mut ks KeysSafe) key_import_add(name string, seed []u8) !PrivKey {
|
||||||
|
if name in ks.keys {
|
||||||
|
return error('A key with that name already exists')
|
||||||
|
}
|
||||||
|
|
||||||
|
mnemonic := internal_key_encode(seed) // mnemonic(seed)
|
||||||
|
signkey := libsodium.new_ed25519_signing_key_seed(seed)
|
||||||
|
privkey := libsodium.new_private_key_from_signing_ed25519(signkey)
|
||||||
|
|
||||||
|
// console.print_debug("===== SEED ====")
|
||||||
|
// console.print_debug(seed)
|
||||||
|
// console.print_debug(mnemonic)
|
||||||
|
|
||||||
|
pk := PrivKey{
|
||||||
|
name: name
|
||||||
|
mnemonic: mnemonic
|
||||||
|
privkey: privkey
|
||||||
|
signkey: signkey
|
||||||
|
}
|
||||||
|
|
||||||
|
ks.key_add(pk)!
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ks KeysSafe) get(name string) !PrivKey {
|
||||||
|
if !ks.exists(name) {
|
||||||
|
return error('key not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
return ks.keys[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ks KeysSafe) exists(name string) bool {
|
||||||
|
return name in ks.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ks KeysSafe) key_add(pk PrivKey) ! {
|
||||||
|
ks.keys[pk.name] = pk
|
||||||
|
|
||||||
|
// do not persist keys if keysafe is not loaded
|
||||||
|
// this mean we are probably loading keys from file
|
||||||
|
if ks.loaded {
|
||||||
|
ks.persist()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ks KeysSafe) persist() {
|
||||||
|
console.print_debug('[+] saving keys to ${ks.path.absolute()}')
|
||||||
|
serialized := ks.serialize()
|
||||||
|
// console.print_debug(serialized)
|
||||||
|
|
||||||
|
encrypted := symmetric_encrypt_blocks(serialized.bytes(), ks.secret)
|
||||||
|
|
||||||
|
mut f := os.create(ks.path.absolute()) or { panic(err) }
|
||||||
|
f.write(encrypted) or { panic(err) }
|
||||||
|
f.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ks KeysSafe) serialize() string {
|
||||||
|
mut pks := PersistantKeysSafe{}
|
||||||
|
|
||||||
|
// serializing mnemonics only
|
||||||
|
for key, val in ks.keys {
|
||||||
|
pks.keys[key] = val.mnemonic
|
||||||
|
}
|
||||||
|
|
||||||
|
export := json.encode(pks)
|
||||||
|
|
||||||
|
return export
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ks KeysSafe) load() {
|
||||||
|
console.print_debug('[+] loading keys from ${ks.path.absolute()}')
|
||||||
|
|
||||||
|
mut f := os.open(ks.path.absolute()) or { panic(err) }
|
||||||
|
|
||||||
|
// read encrypted file
|
||||||
|
filesize := os.file_size(ks.path.absolute())
|
||||||
|
mut encrypted := []u8{len: int(filesize)}
|
||||||
|
|
||||||
|
f.read(mut encrypted) or { panic(err) }
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
// decrypt file using ks secret
|
||||||
|
plaintext := symmetric_decrypt_blocks(encrypted, ks.secret)
|
||||||
|
|
||||||
|
// (try to) decode the json and load keys
|
||||||
|
ks.deserialize(plaintext.bytestr())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ks KeysSafe) deserialize(input string) {
|
||||||
|
mut pks := json.decode(PersistantKeysSafe, input) or {
|
||||||
|
console.print_debug('Failed to decode json, wrong secret or corrupted file: ${err}')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// serializing mnemonics only
|
||||||
|
for name, mnemo in pks.keys {
|
||||||
|
console.print_debug('[+] loading key: ${name}')
|
||||||
|
seed := internal_key_decode(mnemo) // mnemonic.parse(mnemo)
|
||||||
|
|
||||||
|
// console.print_debug("==== SEED ====")
|
||||||
|
// console.print_debug(mnemo)
|
||||||
|
// console.print_debug(seed)
|
||||||
|
|
||||||
|
ks.key_import_add(name, seed) or { panic(err) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.print_debug(ks)
|
||||||
|
}
|
||||||
45
lib/crypt/keysafe/privkey.v
Normal file
45
lib/crypt/keysafe/privkey.v
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
module keysafe
|
||||||
|
|
||||||
|
import libsodium
|
||||||
|
import encoding.hex
|
||||||
|
|
||||||
|
pub struct PrivKey {
|
||||||
|
pub:
|
||||||
|
name string
|
||||||
|
mnemonic string
|
||||||
|
signkey libsodium.SigningKey // master key
|
||||||
|
privkey libsodium.PrivateKey // derivated from master key
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn key_encode(key []u8) string {
|
||||||
|
return '0x' + hex.encode(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve the master public key from PrivKey object
|
||||||
|
// this is the public key as need to be shared to a remote user to verify that we signed with our private key
|
||||||
|
// is shared as hex key in string format (66 chars)
|
||||||
|
pub fn (key PrivKey) master_public() string {
|
||||||
|
x := key.signkey.verify_key.public_key
|
||||||
|
|
||||||
|
mut target := []u8{len: x.len}
|
||||||
|
unsafe { C.memcpy(target.data, &x[0], x.len) }
|
||||||
|
|
||||||
|
return key_encode(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign data with our signing key
|
||||||
|
// data is bytestr
|
||||||
|
// output is []u8 bytestring
|
||||||
|
// to get bytes from string do: mystring.bytes().
|
||||||
|
pub fn (key PrivKey) sign(data []u8) []u8 {
|
||||||
|
return key.signkey.sign(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign data with our signing key.
|
||||||
|
// data is bytestr.
|
||||||
|
// output is hex string.
|
||||||
|
// to get bytes from string do: mystring.bytes().
|
||||||
|
// size of output is ?
|
||||||
|
pub fn (key PrivKey) sign_hex(data []u8) string {
|
||||||
|
return hex.encode(key.sign(data))
|
||||||
|
}
|
||||||
41
lib/crypt/keysafe/pubkey.v
Normal file
41
lib/crypt/keysafe/pubkey.v
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
module keysafe
|
||||||
|
|
||||||
|
import libsodium
|
||||||
|
import encoding.hex
|
||||||
|
|
||||||
|
pub struct PubKey {
|
||||||
|
pub:
|
||||||
|
name string
|
||||||
|
source PrivKey // ourself (private key, to sign message)
|
||||||
|
remote []u8 // target public key (to encrypt)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pubkey_new(name string, myself PrivKey, remote string) !PubKey {
|
||||||
|
parsed := hex.decode(remote.substr(2, remote.len))!
|
||||||
|
|
||||||
|
// convert SigningKey to PrivateKey (ed25519 > x25519)
|
||||||
|
// to allow encryption and decryption
|
||||||
|
|
||||||
|
target := []u8{len: libsodium.public_key_size}
|
||||||
|
libsodium.crypto_sign_ed25519_pk_to_curve25519(target.data, parsed[0])
|
||||||
|
|
||||||
|
return PubKey{
|
||||||
|
name: name
|
||||||
|
source: myself
|
||||||
|
remote: target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this will encrypt bytes so that only the owner of this pubkey can decrypt it
|
||||||
|
pub fn (key PubKey) encrypt(data []u8) ![]u8 {
|
||||||
|
box := libsodium.new_box(key.source.privkey, key.remote)
|
||||||
|
return box.encrypt(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify a signed data
|
||||||
|
pub fn (key PubKey) decrypt(data []u8) []u8 {
|
||||||
|
box := libsodium.new_box(key.source.privkey, key.remote)
|
||||||
|
decrypted := box.decrypt(data)
|
||||||
|
|
||||||
|
return decrypted
|
||||||
|
}
|
||||||
47
lib/crypt/keysafe/readme.md
Normal file
47
lib/crypt/keysafe/readme.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Keysafe
|
||||||
|
|
||||||
|
A safe implementation to help you sign, encrypt, decrypt and store your keys locally.
|
||||||
|
|
||||||
|
## Internals
|
||||||
|
|
||||||
|
When loading a keysafe object, you can specify a `directory` and a `secret`.
|
||||||
|
In that directory, a file called `.keys` will be created and encrypted using
|
||||||
|
the `secret` provided (`AES-CBC`).
|
||||||
|
|
||||||
|
Content of that file is a JSON dictionnary of key-name and it's mnemonic,
|
||||||
|
a single mnemonic is enough to derivate `ed25519` and `x25519` keys.
|
||||||
|
|
||||||
|
When loaded, private/public signing key and public/private encryption keys
|
||||||
|
are loaded and ready to be used.
|
||||||
|
|
||||||
|
- `key_generate_add()` generate a new key and store is as specified name
|
||||||
|
- `key_import_add()` import an existing key based on it's seed and specified name
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```v
|
||||||
|
module main
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.crypt.keysafe
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut ks := keysafe.keysafe_get("/tmp/", "helloworld")!
|
||||||
|
println(ks)
|
||||||
|
|
||||||
|
ks.key_generate_add("demo") or { println(err) }
|
||||||
|
println(ks)
|
||||||
|
|
||||||
|
if ks.exists("demo") {
|
||||||
|
println("key demo exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Keys
|
||||||
|
|
||||||
|
Note about keys: when generating a new key, the "master key" is a SigningKey Ed25519 key. From
|
||||||
|
that key, we can derivate a PrivateKey (encrypting key) X25519.
|
||||||
|
|
||||||
|
We can convert public-key only as well. On public key exchange, please always exchange the public SigningKey
|
||||||
|
(aka the master key for us). Based on that SignigKey, we can derivate the Encyption PublicKey and KeysSafe
|
||||||
|
does it for you.
|
||||||
30
lib/crypt/keysafe/verifkey.v
Normal file
30
lib/crypt/keysafe/verifkey.v
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
module keysafe
|
||||||
|
|
||||||
|
import libsodium
|
||||||
|
import encoding.hex
|
||||||
|
|
||||||
|
pub struct VerifyKey {
|
||||||
|
pub:
|
||||||
|
name string
|
||||||
|
remote libsodium.VerifyKey // target public master key
|
||||||
|
}
|
||||||
|
|
||||||
|
// remote is the public master key which needs to verify
|
||||||
|
pub fn verifykey_new(name string, remote string) !VerifyKey {
|
||||||
|
parsed := hex.decode(remote.substr(2, remote.len))!
|
||||||
|
|
||||||
|
v := [libsodium.public_key_size]u8{}
|
||||||
|
unsafe { C.memcpy(&v[0], parsed.data, libsodium.public_key_size) }
|
||||||
|
|
||||||
|
return VerifyKey{
|
||||||
|
name: name
|
||||||
|
remote: libsodium.VerifyKey{
|
||||||
|
public_key: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify a signed data, returns true if signature is correct
|
||||||
|
pub fn (key VerifyKey) verify(data []u8) bool {
|
||||||
|
return key.remote.verify(data)
|
||||||
|
}
|
||||||
36
lib/crypt/openssl/generate.v
Normal file
36
lib/crypt/openssl/generate.v
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
module openssl
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.builder
|
||||||
|
import json
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct OpenSSLGenerateArgs {
|
||||||
|
name string = 'default'
|
||||||
|
domain string = 'myregistry.domain.com'
|
||||||
|
reset bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ossl OpenSSL) generate(args OpenSSLGenerateArgs) !OpenSSLKey {
|
||||||
|
mut r := ossl.new(args)!
|
||||||
|
|
||||||
|
if r.domain.len < 6 {
|
||||||
|
return error('need to give domain and needs to be bigger than 6 chars. \n${r}')
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := '
|
||||||
|
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ${r.path_key.path} -addext "subjectAltName = DNS:${args.domain}" -subj "/C=BE/ST=Ghent/L=Something/O=Global Security/OU=IT Department/CN=${args.domain}" -x509 -days 365 -out ${r.path_cert.path}
|
||||||
|
'
|
||||||
|
|
||||||
|
mut b := builder.new()!
|
||||||
|
mut node := b.node_local()!
|
||||||
|
|
||||||
|
node.exec(cmd: cmd)!
|
||||||
|
|
||||||
|
r.hexhash()!
|
||||||
|
|
||||||
|
s := json.encode(r)
|
||||||
|
|
||||||
|
r.path_json.write(s)!
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
69
lib/crypt/openssl/generate_ca.v
Normal file
69
lib/crypt/openssl/generate_ca.v
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
module openssl
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.builder
|
||||||
|
import json
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct OpenSSLCAGenerateArgs {
|
||||||
|
name string = 'default'
|
||||||
|
domain string = 'myregistry.domain.com'
|
||||||
|
reset bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ossl OpenSSL) generate_ca(args OpenSSLGenerateArgs) !OpenSSLKey {
|
||||||
|
mut r := ossl.new(args)!
|
||||||
|
|
||||||
|
if r.domain.len < 6 {
|
||||||
|
return error('need to give domain and needs to be bigger than 6 chars. \n${r}')
|
||||||
|
}
|
||||||
|
|
||||||
|
mut b := builder.new()!
|
||||||
|
mut node := b.node_local()!
|
||||||
|
|
||||||
|
// info on https://mariadb.com/docs/xpand/security/data-in-transit-encryption/create-self-signed-certificates-keys-openssl/
|
||||||
|
|
||||||
|
cmd := '
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
openssl genrsa 2048 > ca-key.pem
|
||||||
|
|
||||||
|
#Creating the Certificate Authoritys Certificate and Keys
|
||||||
|
openssl req -new -x509 -nodes -days 365000 -key ca-key.pem -out ca-cert.pem -subj "/C=BE/ST=Ghent/L=Something/O=Global Security/OU=IT Department/CN=${args.domain}"
|
||||||
|
|
||||||
|
openssl req -newkey rsa:2048 -nodes -days 365000 -keyout server-key.pem -out server-req.pem
|
||||||
|
|
||||||
|
openssl x509 -req -days 365000 -set_serial 01 -in server-req.pem -out server-cert.pem -CA ca-cert.pem -CAkey ca-key.pem
|
||||||
|
|
||||||
|
rm -rf /tmp/w
|
||||||
|
mkdir -p /tmp/w
|
||||||
|
cd /tmp/w
|
||||||
|
|
||||||
|
openssl genrsa 2048 > ca-key.pem
|
||||||
|
|
||||||
|
#Creating the Certificate Authoritys Certificate and Keys
|
||||||
|
openssl req -new -x509 -nodes -days 365000 -key ca-key.pem -out ca-cert.pem -subj "/C=BE/ST=Ghent/L=Something/O=Global Security/OU=IT Department/CN=registry.test.com"
|
||||||
|
|
||||||
|
openssl req -newkey rsa:2048 -nodes -days 365000 -keyout server-key.pem -out server-req.pem -subj "/C=BE/ST=Ghent/L=Something/O=Global Security/OU=IT Department/CN=registry.test.com"
|
||||||
|
|
||||||
|
openssl x509 -req -days 365000 -set_serial 01 -in server-req.pem -out server-cert.pem -CA ca-cert.pem -CAkey ca-key.pem
|
||||||
|
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
|
node.exec(cmd: cmd)!
|
||||||
|
|
||||||
|
cmd2 := '
|
||||||
|
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ${r.path_key.path} -addext "subjectAltName = DNS:${args.domain}" -subj "/C=BE/ST=Ghent/L=Something/O=Global Security/OU=IT Department/CN=${args.domain}" -x509 -days 365 -out ${r.path_cert.path}
|
||||||
|
'
|
||||||
|
|
||||||
|
node.exec(cmd: cmd2)!
|
||||||
|
|
||||||
|
r.hexhash()!
|
||||||
|
|
||||||
|
s := json.encode(r)
|
||||||
|
|
||||||
|
r.path_json.write(s)!
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
60
lib/crypt/openssl/get.v
Normal file
60
lib/crypt/openssl/get.v
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
module openssl
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.core.pathlib { Path }
|
||||||
|
import json
|
||||||
|
|
||||||
|
pub struct OpenSSLKey {
|
||||||
|
pub mut:
|
||||||
|
name string
|
||||||
|
domain string
|
||||||
|
md5 string
|
||||||
|
path_key Path
|
||||||
|
path_cert Path
|
||||||
|
path_json Path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ossl OpenSSL) new(args OpenSSLGenerateArgs) !OpenSSLKey {
|
||||||
|
path_key := '${ossl.certpath.path}/${args.name}.key'
|
||||||
|
path_cert := '${ossl.certpath.path}/${args.name}.crt'
|
||||||
|
path_json := '${ossl.certpath.path}/${args.name}.json'
|
||||||
|
mut path_keyo := pathlib.get(path_key)
|
||||||
|
mut path_certo := pathlib.get(path_cert)
|
||||||
|
mut path_jsono := pathlib.get(path_json)
|
||||||
|
|
||||||
|
if args.reset {
|
||||||
|
path_keyo.delete()!
|
||||||
|
path_certo.delete()!
|
||||||
|
path_jsono.delete()!
|
||||||
|
}
|
||||||
|
|
||||||
|
r := OpenSSLKey{
|
||||||
|
name: args.name
|
||||||
|
domain: args.domain
|
||||||
|
path_key: path_keyo
|
||||||
|
path_cert: path_certo
|
||||||
|
path_json: path_jsono
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ossl OpenSSL) exists(args OpenSSLGenerateArgs) !bool {
|
||||||
|
mut r := ossl.new(args)!
|
||||||
|
|
||||||
|
if r.path_key.exists() && r.path_cert.exists() && r.path_json.exists() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// will get openssl key, from fs if exists, otherwise it will generate
|
||||||
|
pub fn (mut ossl OpenSSL) get(args OpenSSLGenerateArgs) !OpenSSLKey {
|
||||||
|
mut r := ossl.new(args)!
|
||||||
|
if r.path_json.exists() {
|
||||||
|
jsontext := r.path_json.read()!
|
||||||
|
return json.decode(OpenSSLKey, jsontext)
|
||||||
|
} else {
|
||||||
|
return ossl.generate(args)!
|
||||||
|
}
|
||||||
|
}
|
||||||
16
lib/crypt/openssl/key.v
Normal file
16
lib/crypt/openssl/key.v
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module openssl
|
||||||
|
|
||||||
|
import crypto.md5
|
||||||
|
|
||||||
|
// give md5 hash of key (concatenate the key+cert)
|
||||||
|
pub fn (mut key OpenSSLKey) hexhash() !string {
|
||||||
|
mut out := ''
|
||||||
|
out += key.path_key.read()!
|
||||||
|
out += key.path_cert.read()!
|
||||||
|
|
||||||
|
res := md5.hexhash(out)
|
||||||
|
|
||||||
|
key.md5 = res
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
23
lib/crypt/openssl/openssl.v
Normal file
23
lib/crypt/openssl/openssl.v
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
module openssl
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.core.pathlib { Path }
|
||||||
|
|
||||||
|
pub struct OpenSSL {
|
||||||
|
certpath Path
|
||||||
|
}
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct OpenSSLArgs {
|
||||||
|
certpath string = '~/.openssl'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(args OpenSSLArgs) !OpenSSL {
|
||||||
|
if args.certpath.len < 3 {
|
||||||
|
return error('need to give certpath and needs to be bigger than 3 chars')
|
||||||
|
}
|
||||||
|
mut datapath := pathlib.get_dir(path: args.certpath, create: true)!
|
||||||
|
mut ossl := OpenSSL{
|
||||||
|
certpath: datapath
|
||||||
|
}
|
||||||
|
return ossl
|
||||||
|
}
|
||||||
33
lib/crypt/pgp/pgp.v
Normal file
33
lib/crypt/pgp/pgp.v
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
module pgp
|
||||||
|
|
||||||
|
// import freeflowuniverse.herolib.builder
|
||||||
|
import os
|
||||||
|
|
||||||
|
pub enum PGPFactoryStatus {
|
||||||
|
init
|
||||||
|
ok
|
||||||
|
error
|
||||||
|
}
|
||||||
|
|
||||||
|
@[heap]
|
||||||
|
struct PGPFactory {
|
||||||
|
mut:
|
||||||
|
path string
|
||||||
|
instances map[string]PGPInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// needed to get singleton
|
||||||
|
fn init2() PGPFactory {
|
||||||
|
mut f := PGPFactory{}
|
||||||
|
// untill we have pgp bindings to the vlang module, we prob need to use command line
|
||||||
|
f.path = '...'
|
||||||
|
f.cmd = '...'
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// singleton creation
|
||||||
|
const factory = init2()
|
||||||
|
|
||||||
|
pub fn get() &PGPFactory {
|
||||||
|
return &factory
|
||||||
|
}
|
||||||
13
lib/crypt/pgp/pgp_cmds.v
Normal file
13
lib/crypt/pgp/pgp_cmds.v
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
module pgp
|
||||||
|
|
||||||
|
// import freeflowuniverse.herolib.builder
|
||||||
|
import os
|
||||||
|
|
||||||
|
// list all instances
|
||||||
|
fn (pgp PGPFactory) list() ?[]&PGPInstance {
|
||||||
|
mut res := []&PGPInstance{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy all instances
|
||||||
|
fn (pgp PGPFactory) destroy() {
|
||||||
|
}
|
||||||
60
lib/crypt/pgp/pgp_instance.v
Normal file
60
lib/crypt/pgp/pgp_instance.v
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
module pgp
|
||||||
|
|
||||||
|
// import freeflowuniverse.herolib.builder
|
||||||
|
import os
|
||||||
|
|
||||||
|
@[heap]
|
||||||
|
struct PGPInstance {
|
||||||
|
mut:
|
||||||
|
name string
|
||||||
|
pubkey string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut f PGPFactory) new(name string) ?&PGPInstance {
|
||||||
|
mut i := PGPInstance{
|
||||||
|
name: name
|
||||||
|
}
|
||||||
|
f.instances[name] = &i
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut f PGPFactory) get(name string) ?&PGPInstance {
|
||||||
|
if name !in f.instances {
|
||||||
|
return error('cannot find pgp instance with name ${name}')
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.instances[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign a piece of content, return signature
|
||||||
|
fn (f PGPInstance) sign(content string) ?Signature {
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt for private usage (is this relevant)
|
||||||
|
fn (f PGPInstance) encrypt_self(content string) ?CryptData {
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt for other person, so they can only decrypt
|
||||||
|
fn (f PGPInstance) encrypt_other(pubkey Pubkey, content string) ?CryptData {
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt for other person, so they can only decrypt
|
||||||
|
// sign using your own pgp key
|
||||||
|
fn (f PGPInstance) encrypt_sign_other(pubkey Pubkey, content string) ?CryptData {
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify agains own key
|
||||||
|
fn (f PGPInstance) verify_self(pubkey Pubkey, signature Signature, content string) ?string {
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify with pub key of other
|
||||||
|
fn (f PGPInstance) verify_other(pubkey Pubkey, signature Signature, content string) ?string {
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt with own key
|
||||||
|
fn (f PGPInstance) decrypt(content CryptData) ?string {
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt with own key and also verify (is counterpart of encrypt_sign_other)
|
||||||
|
fn (f PGPInstance) decrypt_verify(content CryptData) ?string {
|
||||||
|
}
|
||||||
37
lib/crypt/pgp/pgp_model.v
Normal file
37
lib/crypt/pgp/pgp_model.v
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
module pgp
|
||||||
|
|
||||||
|
// import freeflowuniverse.herolib.builder
|
||||||
|
import os
|
||||||
|
|
||||||
|
pub struct Pubkey {
|
||||||
|
mut:
|
||||||
|
pubkey string
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate if pubkey is valid
|
||||||
|
fn (mut pubkey Pubkey) validate() bool {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Signature {
|
||||||
|
mut:
|
||||||
|
signature string
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate if Signature is valid
|
||||||
|
fn (mut signature Signature) validate() bool {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CryptData {
|
||||||
|
mut:
|
||||||
|
data string
|
||||||
|
signature Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate if CryptData is valid
|
||||||
|
fn (mut data CryptData) validate() bool {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut data CryptData) verify() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: what are the methods we need?
|
||||||
6
lib/crypt/pgp/readme.md
Normal file
6
lib/crypt/pgp/readme.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# PGP interface
|
||||||
|
|
||||||
|
> not implemented yet
|
||||||
|
|
||||||
|
> could use crpgp for it, but it became somewhat complicated
|
||||||
|
|
||||||
147
lib/crypt/secp256k1/README.md
Normal file
147
lib/crypt/secp256k1/README.md
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
# libsecp256k1
|
||||||
|
|
||||||
|
This is a lib256k1 binding for vlang.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
make sure the lib is installed
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install secp256k1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ubuntu
|
||||||
|
|
||||||
|
Compile latest release, version included in Ubuntu is outdated.
|
||||||
|
|
||||||
|
```
|
||||||
|
apt-get install -y build-essential wget autoconf libtool
|
||||||
|
|
||||||
|
wget https://github.com/bitcoin-core/secp256k1/archive/refs/tags/v0.3.2.tar.gz
|
||||||
|
tar -xvf v0.3.2.tar.gz
|
||||||
|
|
||||||
|
cd secp256k1-0.3.2/
|
||||||
|
./autogen.sh
|
||||||
|
./configure
|
||||||
|
make -j 5
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arch
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pacman -Su extra/libsecp256k1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gentoo
|
||||||
|
|
||||||
|
```bash
|
||||||
|
emerge dev-libs/libsecp256k1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [x] Generate EC keys
|
||||||
|
- [x] Load existing EC keys
|
||||||
|
- [x] Serialize keys
|
||||||
|
- [x] Derivate shared key
|
||||||
|
- [x] Sign using ECDSA
|
||||||
|
- [x] Verify ECDSA signature
|
||||||
|
- [x] Sign using Schnorr
|
||||||
|
- [x] Verify a Schnorr signature
|
||||||
|
- [ ] Support multi-signature with Schnorr
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
There are 4 differents things / features to understand in this secp256k1 implementation (wrapper).
|
||||||
|
|
||||||
|
### Public and Privaye keys for secp256k1
|
||||||
|
|
||||||
|
This is a simple private/public key schema. This wrapper deals with hexdump of keys.
|
||||||
|
|
||||||
|
- Private key is `32 bytes` long (eg: `0x4a21f247ff3744e211e95ec478d5aba94a1d6d8bed613e8a9faece6d048399fc`)
|
||||||
|
- Public key is `33 bytes` long (eg: `0x02df72fc4fa607ca3478446750bf9f8510242c4fa5849e77373d71104cd0c82ea0`)
|
||||||
|
|
||||||
|
In this library, you can instanciate a secp256k1 object from 3 ways:
|
||||||
|
```vlang
|
||||||
|
import freeflowuniverse.herolib.crypt.secp256k1
|
||||||
|
secp256k1.new()
|
||||||
|
```
|
||||||
|
Constructor without any arguments, will generate a new private and public key
|
||||||
|
|
||||||
|
```vlang
|
||||||
|
secp256k1.new(privkey: '0x4a21f247ff3744e211e95ec478d5aba94a1d6d8bed613e8a9faece6d048399fc')
|
||||||
|
```
|
||||||
|
Using `privkey` argument, this will create an object from private key and generate corresponding public key
|
||||||
|
|
||||||
|
```vlang
|
||||||
|
secp256k1.new(pubkey: '0x02df72fc4fa607ca3478446750bf9f8510242c4fa5849e77373d71104cd0c82ea0')
|
||||||
|
```
|
||||||
|
Using `privkey` argument, this will create an object with only the public key,
|
||||||
|
which can be used for shared key or signature verification
|
||||||
|
|
||||||
|
### Shared Keys
|
||||||
|
|
||||||
|
Library `secp256k1` have one feature which allows you to derivate a `shared intermediate common key` from
|
||||||
|
the private key of one party and the public key from the other party.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
- Shared key from `Bob Private Key` + `Alice Public Key` = `Shared Key`
|
||||||
|
- Shared key from `Alice Private Key` + `Bob Public Key` = `Shared Key` (the same)
|
||||||
|
|
||||||
|
Using this feature, with your private key and target public key, you can derivate a `shared (secret) key`
|
||||||
|
that only you both knows. This is really interresting to switch to a symetric encryption using that key
|
||||||
|
as encryption key or use any well known secret without exchanging it.
|
||||||
|
|
||||||
|
To use the shared key feature, just call the `sharedkeys()` method:
|
||||||
|
```vlang
|
||||||
|
bob := secp256k1.new(privhex: '0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83')!
|
||||||
|
alicepub := secp256k1.new(pubkey: '0x034a87ad6fbf83d89a91c257d4cc038828c6ed9104738ffd4bb7e5069858d4767b')!
|
||||||
|
|
||||||
|
shared := bob.sharedkeys(alicepub)
|
||||||
|
// shared = 0xf114df29d930f0cd37f62cbca36c46773a42bf87e12edcb35d47c4bfbd20514d
|
||||||
|
```
|
||||||
|
|
||||||
|
This works the same in the opposite direction:
|
||||||
|
```vlang
|
||||||
|
alice := secp256k1.new(privhex: '0x8225825815f42e1c24a2e98714d99fee1a20b5ac864fbcb7a103cd0f37f0ffec')!
|
||||||
|
bobpub := secp256k1.new(pubkey: '0x03310ec949bd4f7fc24f823add1394c78e1e9d70949ccacf094c027faa20d99e21')!
|
||||||
|
|
||||||
|
shared := alice.sharedkeys(bobpub)
|
||||||
|
// shared = 0xf114df29d930f0cd37f62cbca36c46773a42bf87e12edcb35d47c4bfbd20514d (same shared key)
|
||||||
|
```
|
||||||
|
|
||||||
|
### ECDSA Signature
|
||||||
|
|
||||||
|
This is the default signature method. When doing a signature, you don't sign the actual data but you
|
||||||
|
have to sign a hash (sha256) of the data. This payload needs to be fixed length. The return signature
|
||||||
|
is a `64 bytes` long response.
|
||||||
|
|
||||||
|
When doing a signature using ecdsa method, you sign using the private key and verify using the public key
|
||||||
|
of the same party. If **Bob** sign something, you have to verify using **Bob** public key is the signature matches.
|
||||||
|
|
||||||
|
If signature matches, that mean that is really **Bob** who signed the hash.
|
||||||
|
Here, you need the signature and the message separately.
|
||||||
|
|
||||||
|
```vlang
|
||||||
|
sstr := alice.sign_str("Hello World !")
|
||||||
|
valid := alicepub.verify_str(sstr, "Hello World !")
|
||||||
|
// valid = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Schnorr Signature
|
||||||
|
|
||||||
|
This is the new prefered signature method. In theory, this method can in addition be able to sign
|
||||||
|
using multiple parties without storing signature of everyone, signature can be chained but this is not
|
||||||
|
implemented in this wrapper (lack of source documentation and understanding).
|
||||||
|
|
||||||
|
In practice, code wide, wrapper take care to handle everything for you and this really looks like
|
||||||
|
the same way than ecdsa.
|
||||||
|
|
||||||
|
```vlang
|
||||||
|
schnorr_sstr := alice.schnorr_sign_str("Hello World !")
|
||||||
|
valid := alicepub.schnorr_verify_str(schnorr_sstr, "Hello World !")
|
||||||
|
// valid = true
|
||||||
|
```
|
||||||
351
lib/crypt/secp256k1/secp256k1.v
Normal file
351
lib/crypt/secp256k1/secp256k1.v
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
@[translated]
|
||||||
|
module secp256k1
|
||||||
|
|
||||||
|
import encoding.hex
|
||||||
|
import crypto.sha256
|
||||||
|
import encoding.base64
|
||||||
|
|
||||||
|
#include "@VMODROOT/secp256k1mod.h"
|
||||||
|
|
||||||
|
#flag @VMODROOT/secp256k1mod.o
|
||||||
|
#flag -lsecp256k1
|
||||||
|
#flag -DNO_SECP_MAIN
|
||||||
|
#flag darwin -I/opt/homebrew/include
|
||||||
|
#flag darwin -L/opt/homebrew/lib
|
||||||
|
|
||||||
|
// linux: require libsecp256k1-dev
|
||||||
|
// macos: require brew install secp256k1
|
||||||
|
|
||||||
|
//
|
||||||
|
// struct definitions
|
||||||
|
//
|
||||||
|
struct Secp256k1_pubkey {
|
||||||
|
data [64]u8
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Secp256k1_xonly_pubkey {
|
||||||
|
data [64]u8
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Secp256k1_ecdsa_signature {
|
||||||
|
data [64]u8
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Secp256k1_keypair {
|
||||||
|
data [96]u8
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Secp256k1_t {
|
||||||
|
kntxt &C.secp256k1_context
|
||||||
|
seckey &u8
|
||||||
|
compressed &u8
|
||||||
|
pubkey Secp256k1_pubkey
|
||||||
|
xcompressed &u8
|
||||||
|
xpubkey Secp256k1_xonly_pubkey
|
||||||
|
keypair Secp256k1_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Secp256k1_sign_t {
|
||||||
|
sig Secp256k1_ecdsa_signature
|
||||||
|
serialized &u8
|
||||||
|
length usize
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Secp256k1_signature {
|
||||||
|
cctx &C.secp256k1_sign_t
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Secp256k1 {
|
||||||
|
cctx &Secp256k1_t
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// prototypes
|
||||||
|
//
|
||||||
|
fn C.secp256k1_new() &Secp256k1_t
|
||||||
|
|
||||||
|
fn C.secp256k1_schnorr_verify(secp &Secp256k1_t, signature &u8, siglen usize, hash &u8, hashlen usize) int
|
||||||
|
|
||||||
|
fn C.secp256k1_schnorr_sign_hash(secp &Secp256k1_t, hash &u8, length usize) &u8
|
||||||
|
|
||||||
|
fn C.secp256k1_sign_verify(secp &Secp256k1_t, signature &Secp256k1_sign_t, hash &u8, length usize) int
|
||||||
|
|
||||||
|
fn C.secp256k1_sign_free(signature &Secp256k1_sign_t)
|
||||||
|
|
||||||
|
fn C.secp256k1_load_signature(secp &Secp256k1_t, serialized &u8, length usize) &Secp256k1_sign_t
|
||||||
|
|
||||||
|
fn C.secp256k1_sign_hash(secp &Secp256k1_t, hash &u8, length usize) &u8
|
||||||
|
|
||||||
|
fn C.secp265k1_shared_key(private &Secp256k1_t, public &Secp256k1_t) &u8
|
||||||
|
|
||||||
|
fn C.secp256k1_load_key(secp &Secp256k1_t, key &u8) int
|
||||||
|
|
||||||
|
fn C.secp256k1_load_private_key(secp &Secp256k1_t, key &u8) int
|
||||||
|
|
||||||
|
fn C.secp256k1_load_public_key(secp &Secp256k1_t, key &u8) int
|
||||||
|
|
||||||
|
fn C.secp256k1_free(secp &Secp256k1_t)
|
||||||
|
|
||||||
|
fn C.secp256k1_dumps(secp &Secp256k1_t)
|
||||||
|
|
||||||
|
fn C.secp256k1_export(secp &Secp256k1_t) &u8
|
||||||
|
|
||||||
|
fn C.secp256k1_private_key(secp &Secp256k1_t) &u8
|
||||||
|
|
||||||
|
fn C.secp256k1_public_key(secp &Secp256k1_t) &u8
|
||||||
|
|
||||||
|
fn C.secp256k1_generate_key(secp &Secp256k1_t) int
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct Secp256NewArgs {
|
||||||
|
pub:
|
||||||
|
pubhex string // public key hex (eg 03310ec949bd4f7fc24f823add1394c78e1e9d70949ccacf094c027faa20d99e21)
|
||||||
|
privhex string // private key hex (eg 478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83)
|
||||||
|
pubbase64 string
|
||||||
|
privbase64 string
|
||||||
|
// key []u8 // is in binary form (not implemented)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a Secp256k1 key, can start from an existing key in string hex format (starts with 0x)
|
||||||
|
// parameters:
|
||||||
|
// privhex: private key in hex format (full features will be available)
|
||||||
|
// pubhex: public key in hex format (reduced features available)
|
||||||
|
//
|
||||||
|
// keyhex string // e.g. 0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83
|
||||||
|
// // keyhex is still supported for _backward_ compatibility only, please do not use anymore
|
||||||
|
//
|
||||||
|
// key []u8 // is in binary form (not implemented)
|
||||||
|
// generate bool = true // default will generate a new key .
|
||||||
|
pub fn new(args_ Secp256NewArgs) !Secp256k1 {
|
||||||
|
mut args := args_
|
||||||
|
|
||||||
|
secp := Secp256k1{}
|
||||||
|
secp.cctx = C.secp256k1_new()
|
||||||
|
|
||||||
|
// if args.key.len > 0 && args.privhex.len > 0 {
|
||||||
|
// return error('cannot specify privhex and key at same time')
|
||||||
|
// }
|
||||||
|
|
||||||
|
if args.privhex.len > 0 && args.pubhex.len > 0 {
|
||||||
|
return error('cannot specify private and public key at same time')
|
||||||
|
}
|
||||||
|
if args.privhex.len > 0 {
|
||||||
|
// same as keyhex (backward compatibility)
|
||||||
|
// load key from hex like 0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83
|
||||||
|
// key is the private key
|
||||||
|
if !(args.privhex.starts_with('0x')) {
|
||||||
|
args.privhex = '0x${args.privhex}'
|
||||||
|
}
|
||||||
|
load := C.secp256k1_load_private_key(secp.cctx, args.privhex.str)
|
||||||
|
if load > 0 {
|
||||||
|
return error('invalid private key')
|
||||||
|
}
|
||||||
|
} else if args.pubhex.len > 0 {
|
||||||
|
// load key from hex like 0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83
|
||||||
|
// key is the public key, this only allow signature check, shared keys, etc.
|
||||||
|
if !(args.pubhex.starts_with('0x')) {
|
||||||
|
args.pubhex = '0x${args.pubhex}'
|
||||||
|
}
|
||||||
|
load := C.secp256k1_load_public_key(secp.cctx, args.pubhex.str)
|
||||||
|
if load > 0 {
|
||||||
|
return error('invalid public key')
|
||||||
|
}
|
||||||
|
} else if args.privbase64.len > 0 {
|
||||||
|
keybin := base64.decode(args.privbase64)
|
||||||
|
keyhex := hex.encode(keybin)
|
||||||
|
keyhex2 := '0x${keyhex}'
|
||||||
|
return new(privhex: keyhex2)!
|
||||||
|
} else if args.pubbase64.len > 0 {
|
||||||
|
keybin := base64.decode(args.pubbase64)
|
||||||
|
keyhex := hex.encode(keybin)
|
||||||
|
keyhex2 := '0x${keyhex}'
|
||||||
|
return new(pubhex: keyhex2)!
|
||||||
|
} else {
|
||||||
|
C.secp256k1_generate_key(secp.cctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement the binary key input
|
||||||
|
// TODO: check format in side and report properly
|
||||||
|
|
||||||
|
// dumps keys for debugging purpose
|
||||||
|
// secp.keys()
|
||||||
|
|
||||||
|
return secp
|
||||||
|
}
|
||||||
|
|
||||||
|
// request keys dump from low level library
|
||||||
|
// this basically prints keys from internal objects (private, public, shared, x-only, ...)
|
||||||
|
// warning: this is for debug purpose
|
||||||
|
fn (s Secp256k1) keys() {
|
||||||
|
C.secp256k1_dumps(s.cctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// export private key
|
||||||
|
// backward compatibility, please use private_key() and public_key() methods
|
||||||
|
pub fn (s Secp256k1) export() string {
|
||||||
|
key := C.secp256k1_export(s.cctx)
|
||||||
|
return unsafe { key.vstring() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// with a private key in pair with a public key, secp256k1 can derivate a shared
|
||||||
|
// key which is the same for both parties, this is really interresting to use for example
|
||||||
|
// that shared keys for symetric encryption key since it's private but common
|
||||||
|
//
|
||||||
|
// example: sharedkey(bobpriv + alicepub) = abcdef
|
||||||
|
// sharedkey(alicepriv + bobpub) = abcdef
|
||||||
|
//
|
||||||
|
// both parties can use their own private key with target public key to derivate the same
|
||||||
|
// shared commun key, this key is unique with that pair.
|
||||||
|
pub fn (s Secp256k1) sharedkeys(target Secp256k1) []u8 {
|
||||||
|
shr := C.secp265k1_shared_key(s.cctx, target.cctx)
|
||||||
|
return unsafe { shr.vbytes(32) } // 32 bytes shared key
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) sharedkeys_hex(target Secp256k1) string {
|
||||||
|
keybin := s.sharedkeys(target)
|
||||||
|
return hex.encode(keybin)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) sharedkeys_base64(target Secp256k1) string {
|
||||||
|
keybin := s.sharedkeys(target)
|
||||||
|
return base64.encode(keybin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns private key in hex format
|
||||||
|
pub fn (s Secp256k1) private_key_hex() string {
|
||||||
|
key := C.secp256k1_private_key(s.cctx)
|
||||||
|
return unsafe { key.vstring()[2..] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) private_key_base64() string {
|
||||||
|
key := s.private_key_hex()
|
||||||
|
keybin := hex.decode(key) or { panic("can't decode hex") }
|
||||||
|
return base64.encode(keybin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return public key in hex format
|
||||||
|
pub fn (s Secp256k1) public_key_hex() string {
|
||||||
|
key := C.secp256k1_public_key(s.cctx)
|
||||||
|
return unsafe { key.vstring()[2..] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) public_key_base64() string {
|
||||||
|
key := s.public_key_hex()
|
||||||
|
keybin := hex.decode(key) or { panic("can't decode hex") }
|
||||||
|
return base64.encode(keybin)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// sign (ecdsa) data
|
||||||
|
// - we force user to pass data to ensure we hash the right way
|
||||||
|
// data to ensure signature is valid and safe
|
||||||
|
//
|
||||||
|
pub fn (s Secp256k1) sign_data(data []u8) []u8 {
|
||||||
|
// hash data
|
||||||
|
h256 := sha256.sum(data)
|
||||||
|
signature := C.secp256k1_sign_hash(s.cctx, h256.data, h256.len)
|
||||||
|
|
||||||
|
return unsafe { signature.vbytes(64) } // 64 bytes signature
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a hex string of the signature
|
||||||
|
pub fn (s Secp256k1) sign_data_hex(data []u8) string {
|
||||||
|
payload := s.sign_data(data)
|
||||||
|
return hex.encode(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) sign_data_base64(data []u8) string {
|
||||||
|
payload := s.sign_data(data)
|
||||||
|
return base64.encode(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) sign_str(data string) []u8 {
|
||||||
|
return s.sign_data(data.bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a hex string of the signature
|
||||||
|
pub fn (s Secp256k1) sign_str_hex(data string) string {
|
||||||
|
return s.sign_data_hex(data.bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) sign_str_base64(data string) string {
|
||||||
|
payload := s.sign_data(data.bytes())
|
||||||
|
return base64.encode(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// verify a signature
|
||||||
|
//
|
||||||
|
pub fn (s Secp256k1) verify_data(signature []u8, data []u8) bool {
|
||||||
|
// todo: check size signature
|
||||||
|
sig := Secp256k1_signature{}
|
||||||
|
sig.cctx = C.secp256k1_load_signature(s.cctx, signature.data, signature.len)
|
||||||
|
|
||||||
|
// compute data hash to ensure we do it correctly
|
||||||
|
// - do not trust the user, do it ourself -
|
||||||
|
h256 := sha256.sum(data)
|
||||||
|
valid := C.secp256k1_sign_verify(s.cctx, sig.cctx, h256.data, h256.len)
|
||||||
|
if valid == 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) verify_str_base64(signature string, input string) bool {
|
||||||
|
signature2 := base64.decode(signature)
|
||||||
|
return s.verify_data(signature2, input.bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) verify_str_hex(signature string, input string) bool {
|
||||||
|
signature2 := hex.decode(signature) or { panic("couldn't decode 64") }
|
||||||
|
return s.verify_data(signature2, input.bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// sign (schnorr) data
|
||||||
|
// - we force user to pass data to ensure we hash the right way
|
||||||
|
// data to ensure signature is valid and safe
|
||||||
|
//
|
||||||
|
pub fn (s Secp256k1) schnorr_sign_data(data []u8) []u8 {
|
||||||
|
// hash data
|
||||||
|
h256 := sha256.sum(data)
|
||||||
|
signature := C.secp256k1_schnorr_sign_hash(s.cctx, h256.data, h256.len)
|
||||||
|
|
||||||
|
return unsafe { signature.vbytes(64) } // 64 bytes signature
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a hex string of the signature
|
||||||
|
pub fn (s Secp256k1) schnorr_sign_data_hex(data []u8) string {
|
||||||
|
payload := s.schnorr_sign_data(data)
|
||||||
|
return hex.encode(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) schnorr_sign_str(data string) []u8 {
|
||||||
|
return s.schnorr_sign_data(data.bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a hex string of the signature
|
||||||
|
pub fn (s Secp256k1) schnorr_sign_str_hex(data string) string {
|
||||||
|
return s.schnorr_sign_data_hex(data.bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// verify a signature
|
||||||
|
//
|
||||||
|
pub fn (s Secp256k1) schnorr_verify_data(signature []u8, data []u8) bool {
|
||||||
|
// compute data hash to ensure we do it correctly
|
||||||
|
// - do not trust the user, do it ourself -
|
||||||
|
h256 := sha256.sum(data)
|
||||||
|
valid := C.secp256k1_schnorr_verify(s.cctx, signature.data, signature.len, h256.data,
|
||||||
|
h256.len)
|
||||||
|
if valid == 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s Secp256k1) schnorr_verify_str(signature []u8, input string) bool {
|
||||||
|
return s.schnorr_verify_data(signature, input.bytes())
|
||||||
|
}
|
||||||
460
lib/crypt/secp256k1/secp256k1mod.c
Normal file
460
lib/crypt/secp256k1/secp256k1mod.c
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/random.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "secp256k1mod.h"
|
||||||
|
|
||||||
|
static int fill_random(unsigned char* data, size_t size) {
|
||||||
|
#if defined(__linux__) || defined(__FreeBSD__)
|
||||||
|
ssize_t res = getrandom(data, size, 0);
|
||||||
|
if(res < 0 || (size_t) res != size) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__APPLE__) || defined(__OpenBSD__)
|
||||||
|
int res = getentropy(data, size);
|
||||||
|
if(res == 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dumphex(unsigned char *data, size_t size) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
printf("0x");
|
||||||
|
|
||||||
|
for(i = 0; i < size; i++) {
|
||||||
|
printf("%02x", data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *hexifier(unsigned char *data, size_t size) {
|
||||||
|
char *target = calloc(sizeof(char), (size * 2) + 4);
|
||||||
|
char buffer[8];
|
||||||
|
|
||||||
|
strcpy(target, "0x");
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
sprintf(buffer, "%02x", data[i]);
|
||||||
|
strcat(target, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *hexparse(char *input) {
|
||||||
|
if(strncmp(input, "0x", 2) != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t length = strlen(input);
|
||||||
|
|
||||||
|
unsigned char *target = calloc(sizeof(char), length);
|
||||||
|
char *pos = input + 2;
|
||||||
|
|
||||||
|
for(size_t count = 0; count < length - 2; count++) {
|
||||||
|
sscanf(pos, "%2hhx", &target[count]);
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_erase(unsigned char *target, size_t length) {
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
// memory barrier to avoid memset optimization
|
||||||
|
memset(target, 0, length);
|
||||||
|
__asm__ __volatile__("" : : "r"(target) : "memory");
|
||||||
|
#else
|
||||||
|
// if we can't, fill with random, still better than
|
||||||
|
// risking avoid memset
|
||||||
|
fill_random(target, length);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_erase_free(unsigned char *target, size_t length) {
|
||||||
|
secp256k1_erase(target, length);
|
||||||
|
free(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_t *secp256k1_new() {
|
||||||
|
secp256k1_t *secp = malloc(sizeof(secp256k1_t));
|
||||||
|
unsigned char randomize[32];
|
||||||
|
|
||||||
|
secp->kntxt = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||||
|
|
||||||
|
if(!fill_random(randomize, sizeof(randomize))) {
|
||||||
|
printf("[-] failed to generate randomness\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// side-channel protection
|
||||||
|
int val = secp256k1_context_randomize(secp->kntxt, randomize);
|
||||||
|
assert(val);
|
||||||
|
|
||||||
|
// allocate keys and initialize them empty
|
||||||
|
secp->seckey = calloc(sizeof(char), SECKEY_SIZE);
|
||||||
|
secp->compressed = calloc(sizeof(char), COMPPUB_SIZE);
|
||||||
|
secp->xcompressed = calloc(sizeof(char), XSERPUB_SIZE);
|
||||||
|
|
||||||
|
return secp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void secp256k1_free(secp256k1_t *secp) {
|
||||||
|
secp256k1_context_destroy(secp->kntxt);
|
||||||
|
secp256k1_erase_free(secp->seckey, SECKEY_SIZE);
|
||||||
|
secp256k1_erase_free(secp->compressed, COMPPUB_SIZE);
|
||||||
|
secp256k1_erase_free(secp->xcompressed, XSERPUB_SIZE);
|
||||||
|
free(secp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_populate_public_key(secp256k1_t *secp) {
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = secp256k1_xonly_pubkey_from_pubkey(secp->kntxt, &secp->xpubkey, NULL, &secp->pubkey);
|
||||||
|
assert(retval);
|
||||||
|
|
||||||
|
retval = secp256k1_xonly_pubkey_serialize(secp->kntxt, secp->xcompressed, &secp->xpubkey);
|
||||||
|
assert(retval);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_populate_key(secp256k1_t *secp) {
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = secp256k1_ec_pubkey_create(secp->kntxt, &secp->pubkey, secp->seckey);
|
||||||
|
assert(retval);
|
||||||
|
|
||||||
|
size_t len = COMPPUB_SIZE;
|
||||||
|
retval = secp256k1_ec_pubkey_serialize(secp->kntxt, secp->compressed, &len, &secp->pubkey, SECP256K1_EC_COMPRESSED);
|
||||||
|
assert(retval);
|
||||||
|
|
||||||
|
// always compute the xonly pubkey as well, so we don't need to compute
|
||||||
|
// it later for schnorr
|
||||||
|
retval = secp256k1_keypair_create(secp->kntxt, &secp->keypair, secp->seckey);
|
||||||
|
assert(retval);
|
||||||
|
|
||||||
|
return secp256k1_populate_public_key(secp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_generate_key(secp256k1_t *secp) {
|
||||||
|
while(1) {
|
||||||
|
if(!fill_random(secp->seckey, SECKEY_SIZE)) {
|
||||||
|
printf("[-] failed to generate randomness\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(secp256k1_ec_seckey_verify(secp->kntxt, secp->seckey) == 0) {
|
||||||
|
// try again
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return secp256k1_populate_key(secp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// backward compatibility
|
||||||
|
int secp256k1_load_key(secp256k1_t *secp, char *key) {
|
||||||
|
// only allow valid key size
|
||||||
|
if(strlen(key) != (SECKEY_SIZE * 2) + 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unsigned char *binkey = hexparse(key);
|
||||||
|
|
||||||
|
free(secp->seckey);
|
||||||
|
secp->seckey = binkey;
|
||||||
|
|
||||||
|
if(secp256k1_ec_seckey_verify(secp->kntxt, secp->seckey) == 0) {
|
||||||
|
// invalid key
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return secp256k1_populate_key(secp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_load_private_key(secp256k1_t *secp, char *key) {
|
||||||
|
return secp256k1_load_key(secp, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_load_public_key(secp256k1_t *secp, char *key) {
|
||||||
|
// only allow valid key size
|
||||||
|
if(strlen(key) != (COMPPUB_SIZE * 2) + 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unsigned char *binkey = hexparse(key);
|
||||||
|
|
||||||
|
free(secp->compressed);
|
||||||
|
secp->compressed = binkey;
|
||||||
|
|
||||||
|
if(!secp256k1_ec_pubkey_parse(secp->kntxt, &secp->pubkey, secp->compressed, COMPPUB_SIZE)) {
|
||||||
|
printf("[-] failed to load public key\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return secp256k1_populate_public_key(secp);;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char *secp265k1_shared_key(secp256k1_t *private, secp256k1_t *public) {
|
||||||
|
unsigned char *shared = malloc(sizeof(unsigned char) * SHARED_SIZE);
|
||||||
|
|
||||||
|
int val = secp256k1_ecdh(private->kntxt, shared, &public->pubkey, private->seckey, NULL, NULL);
|
||||||
|
assert(val);
|
||||||
|
|
||||||
|
return shared;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *secp256k1_sign_hash(secp256k1_t *secp, unsigned char *hash, size_t length) {
|
||||||
|
secp256k1_sign_t signature;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if(length != SHA256_SIZE) {
|
||||||
|
printf("[-] warning: you should only sign sha-256 hash, size mismatch\n");
|
||||||
|
printf("[-] warning: you get warned\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = secp256k1_ecdsa_sign(secp->kntxt, &signature.sig, hash, secp->seckey, NULL, NULL);
|
||||||
|
assert(retval);
|
||||||
|
|
||||||
|
signature.serialized = malloc(sizeof(unsigned char) * SERSIG_SIZE);
|
||||||
|
|
||||||
|
retval = secp256k1_ecdsa_signature_serialize_compact(secp->kntxt, signature.serialized, &signature.sig);
|
||||||
|
assert(retval);
|
||||||
|
|
||||||
|
return signature.serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_sign_t *secp256k1_load_signature(secp256k1_t *secp, unsigned char *serialized, size_t length) {
|
||||||
|
secp256k1_sign_t *signature;
|
||||||
|
|
||||||
|
if(length != SERSIG_SIZE) {
|
||||||
|
printf("[-] serialized signature length mismatch, expected %u bytes\n", SERSIG_SIZE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature = calloc(sizeof(secp256k1_sign_t), 1);
|
||||||
|
|
||||||
|
signature->length = length;
|
||||||
|
signature->serialized = malloc(length);
|
||||||
|
memcpy(signature->serialized, serialized, length);
|
||||||
|
|
||||||
|
if(!secp256k1_ecdsa_signature_parse_compact(secp->kntxt, &signature->sig, signature->serialized)) {
|
||||||
|
printf("[-] failed to parse the signature\n");
|
||||||
|
// FIXME: cleanup
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
void secp256k1_sign_free(secp256k1_sign_t *signature) {
|
||||||
|
secp256k1_erase_free(signature->serialized, signature->length);
|
||||||
|
free(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_sign_verify(secp256k1_t *secp, secp256k1_sign_t *signature, unsigned char *hash, size_t length) {
|
||||||
|
if(length != SHA256_SIZE) {
|
||||||
|
printf("[-] warning: you should only check sha-256 hash, size mismatch\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return secp256k1_ecdsa_verify(secp->kntxt, &signature->sig, hash, &secp->pubkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *secp256k1_schnorr_sign_hash(secp256k1_t *secp, unsigned char *hash, size_t length) {
|
||||||
|
unsigned char aux[32];
|
||||||
|
unsigned char *signature;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if(length != SHA256_SIZE) {
|
||||||
|
printf("[-] warning: you should only sign sha-256 hash, size mismatch\n");
|
||||||
|
printf("[-] warning: you get warned\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!fill_random(aux, sizeof(aux))) {
|
||||||
|
printf("[-] failed to generate randomness\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature = malloc(sizeof(unsigned char) * SCHSIG_SIZE);
|
||||||
|
|
||||||
|
retval = secp256k1_schnorrsig_sign32(secp->kntxt, signature, hash, &secp->keypair, aux);
|
||||||
|
assert(retval);
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_schnorr_verify(secp256k1_t *secp, unsigned char *signature, size_t siglen, unsigned char *hash, size_t hashlen) {
|
||||||
|
if(hashlen != SHA256_SIZE) {
|
||||||
|
printf("[-] warning: you should only check sha-256 hash, size mismatch\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(siglen != SCHSIG_SIZE) {
|
||||||
|
printf("[-] invalid signature length, should be %u bytes\n", SCHSIG_SIZE);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return secp256k1_schnorrsig_verify(secp->kntxt, signature, hash, hashlen, &secp->xpubkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void secp256k1_dumps(secp256k1_t *secp) {
|
||||||
|
printf("Private Key: ");
|
||||||
|
dumphex(secp->seckey, SECKEY_SIZE);
|
||||||
|
|
||||||
|
printf("Public Key : ");
|
||||||
|
dumphex(secp->compressed, COMPPUB_SIZE);
|
||||||
|
|
||||||
|
printf("X-Only Key : ");
|
||||||
|
dumphex(secp->xcompressed, XSERPUB_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// backward compatibility
|
||||||
|
char *secp256k1_export(secp256k1_t *secp) {
|
||||||
|
return hexifier(secp->seckey, SECKEY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return private key in hex format
|
||||||
|
char *secp256k1_private_key(secp256k1_t *secp) {
|
||||||
|
return secp256k1_export(secp);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *secp256k1_public_key(secp256k1_t *secp) {
|
||||||
|
return hexifier(secp->compressed, COMPPUB_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NO_SECP_MAIN
|
||||||
|
int main() {
|
||||||
|
secp256k1_t *wendy = secp256k1_new();
|
||||||
|
secp256k1_generate_key(wendy);
|
||||||
|
|
||||||
|
printf("Wendy:\n");
|
||||||
|
dumphex(wendy->seckey, SECKEY_SIZE);
|
||||||
|
dumphex(wendy->compressed, COMPPUB_SIZE);
|
||||||
|
dumphex(wendy->xcompressed, XSERPUB_SIZE);
|
||||||
|
|
||||||
|
// bob
|
||||||
|
secp256k1_t *bob = secp256k1_new();
|
||||||
|
secp256k1_load_key(bob, "0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83");
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Bob:\n");
|
||||||
|
dumphex(bob->seckey, SECKEY_SIZE);
|
||||||
|
dumphex(bob->compressed, COMPPUB_SIZE);
|
||||||
|
dumphex(bob->xcompressed, XSERPUB_SIZE);
|
||||||
|
|
||||||
|
// export functions
|
||||||
|
char *priv = secp256k1_private_key(bob);
|
||||||
|
char *pubk = secp256k1_public_key(bob);
|
||||||
|
printf("Private export: %s\n", priv);
|
||||||
|
printf("Public export: %s\n", pubk);
|
||||||
|
free(priv);
|
||||||
|
|
||||||
|
secp256k1_t *bobpub = secp256k1_new();
|
||||||
|
int val = secp256k1_load_public_key(bobpub, "0x03310ec949bd4f7fc24f823add1394c78e1e9d70949ccacf094c027faa20d99e21");
|
||||||
|
printf("Public key loader: %d\n", val);
|
||||||
|
secp256k1_dumps(bobpub);
|
||||||
|
|
||||||
|
// alice
|
||||||
|
secp256k1_t *alice = secp256k1_new();
|
||||||
|
secp256k1_load_key(alice, "0x8225825815f42e1c24a2e98714d99fee1a20b5ac864fbcb7a103cd0f37f0ffec");
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Alice:\n");
|
||||||
|
dumphex(alice->seckey, SECKEY_SIZE);
|
||||||
|
dumphex(alice->compressed, COMPPUB_SIZE);
|
||||||
|
dumphex(alice->xcompressed, XSERPUB_SIZE);
|
||||||
|
|
||||||
|
unsigned char *shared1 = secp265k1_shared_key(bob, alice);
|
||||||
|
unsigned char *shared2 = secp265k1_shared_key(alice, bob);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Shared Key:\n");
|
||||||
|
dumphex(shared1, SHARED_SIZE);
|
||||||
|
dumphex(shared2, SHARED_SIZE);
|
||||||
|
|
||||||
|
secp256k1_erase_free(shared1, SHARED_SIZE);
|
||||||
|
secp256k1_erase_free(shared2, SHARED_SIZE);
|
||||||
|
|
||||||
|
// Hello, world!
|
||||||
|
unsigned char hash[32] = {
|
||||||
|
0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4,
|
||||||
|
0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64,
|
||||||
|
0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34,
|
||||||
|
0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char *sign = secp256k1_sign_hash(bob, hash, sizeof(hash));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Signature (ecdsa):\n");
|
||||||
|
dumphex(sign, SERSIG_SIZE);
|
||||||
|
|
||||||
|
secp256k1_sign_t *sigobj = secp256k1_load_signature(bob, sign, SERSIG_SIZE);
|
||||||
|
int valid = secp256k1_sign_verify(bob, sigobj, hash, sizeof(hash));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Signature valid: %d\n", valid);
|
||||||
|
|
||||||
|
secp256k1_sign_free(sigobj);
|
||||||
|
|
||||||
|
// using bobpub
|
||||||
|
sigobj = secp256k1_load_signature(bobpub, sign, SERSIG_SIZE);
|
||||||
|
valid = secp256k1_sign_verify(bobpub, sigobj, hash, sizeof(hash));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Signature valid (using bob public key only): %d\n", valid);
|
||||||
|
|
||||||
|
secp256k1_erase_free(sign, SERSIG_SIZE);
|
||||||
|
secp256k1_sign_free(sigobj);
|
||||||
|
|
||||||
|
sign = secp256k1_schnorr_sign_hash(bob, hash, sizeof(hash));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Signature (schnorr):\n");
|
||||||
|
dumphex(sign, SCHSIG_SIZE);
|
||||||
|
|
||||||
|
valid = secp256k1_schnorr_verify(bob, sign, SCHSIG_SIZE, hash, sizeof(hash));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Signature valid: %d\n", valid);
|
||||||
|
|
||||||
|
valid = secp256k1_schnorr_verify(bobpub, sign, SCHSIG_SIZE, hash, sizeof(hash));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Signature valid (using bob pubkey key only): %d\n", valid);
|
||||||
|
|
||||||
|
secp256k1_erase_free(sign, SCHSIG_SIZE);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Wendy Export:\n");
|
||||||
|
char *export = secp256k1_export(wendy);
|
||||||
|
printf(">> %s\n", export);
|
||||||
|
free(export);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("Wendy Keys dump:\n");
|
||||||
|
secp256k1_dumps(wendy);
|
||||||
|
|
||||||
|
secp256k1_free(bob);
|
||||||
|
secp256k1_free(alice);
|
||||||
|
secp256k1_free(wendy);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
61
lib/crypt/secp256k1/secp256k1mod.h
Normal file
61
lib/crypt/secp256k1/secp256k1mod.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef SECP256K1_V_MOD
|
||||||
|
#define SECP256K1_V_MOD
|
||||||
|
|
||||||
|
#include <secp256k1.h>
|
||||||
|
#include <secp256k1_ecdh.h>
|
||||||
|
#include <secp256k1_extrakeys.h>
|
||||||
|
#include <secp256k1_schnorrsig.h>
|
||||||
|
|
||||||
|
typedef struct secp256k1_t {
|
||||||
|
secp256k1_context *kntxt; // library context
|
||||||
|
unsigned char *seckey; // ec private key
|
||||||
|
|
||||||
|
unsigned char *compressed; // ec public key serialized
|
||||||
|
secp256k1_pubkey pubkey; // ec public key
|
||||||
|
|
||||||
|
unsigned char *xcompressed; // x-only serialized key
|
||||||
|
secp256k1_xonly_pubkey xpubkey; // x-only public key
|
||||||
|
secp256k1_keypair keypair; // keypair opaque representation
|
||||||
|
// needed for schnorr
|
||||||
|
|
||||||
|
} secp256k1_t;
|
||||||
|
|
||||||
|
typedef struct secp256k1_sign_t {
|
||||||
|
secp256k1_ecdsa_signature sig;
|
||||||
|
unsigned char *serialized;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
} secp256k1_sign_t;
|
||||||
|
|
||||||
|
#define SECKEY_SIZE 32 // secret key size
|
||||||
|
#define SHARED_SIZE 32 // ecdh shared key size
|
||||||
|
#define COMPPUB_SIZE 33 // compressed public key size
|
||||||
|
#define XSERPUB_SIZE 32 // x-only public key serialized size
|
||||||
|
#define SERSIG_SIZE 64 // serialized signature size
|
||||||
|
#define SCHSIG_SIZE 64 // internal schnorr signature size
|
||||||
|
|
||||||
|
#define SHA256_SIZE 32 // sha-256 digest length
|
||||||
|
|
||||||
|
secp256k1_t *secp256k1_new();
|
||||||
|
void secp256k1_free(secp256k1_t *secp);
|
||||||
|
|
||||||
|
int secp256k1_generate_key(secp256k1_t *secp);
|
||||||
|
unsigned char *secp265k1_shared_key(secp256k1_t *private, secp256k1_t *public);
|
||||||
|
unsigned char *secp256k1_sign_hash(secp256k1_t *secp, unsigned char *hash, size_t length);
|
||||||
|
|
||||||
|
secp256k1_sign_t *secp256k1_load_signature(secp256k1_t *secp, unsigned char *serialized, size_t length);
|
||||||
|
int secp256k1_sign_verify(secp256k1_t *secp, secp256k1_sign_t *signature, unsigned char *hash, size_t length);
|
||||||
|
unsigned char *secp256k1_schnorr_sign_hash(secp256k1_t *secp, unsigned char *hash, size_t length);
|
||||||
|
int secp256k1_schnorr_verify(secp256k1_t *secp, unsigned char *signature, size_t siglen, unsigned char *hash, size_t hashlen);
|
||||||
|
void secp256k1_sign_free(secp256k1_sign_t *signature);
|
||||||
|
|
||||||
|
char *secp256k1_export(secp256k1_t *secp);
|
||||||
|
char *secp256k1_private_key(secp256k1_t *secp);
|
||||||
|
char *secp256k1_public_key(secp256k1_t *secp);
|
||||||
|
void secp256k1_dumps(secp256k1_t *secp);
|
||||||
|
int secp256k1_load_key(secp256k1_t *secp, char *key);
|
||||||
|
|
||||||
|
int secp256k1_load_private_key(secp256k1_t *secp, char *key);
|
||||||
|
int secp256k1_load_public_key(secp256k1_t *secp, char *key);
|
||||||
|
#endif
|
||||||
|
|
||||||
112
lib/crypt/secp256k1/secp256k_test.v
Normal file
112
lib/crypt/secp256k1/secp256k_test.v
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
module secp256k1
|
||||||
|
|
||||||
|
import encoding.hex
|
||||||
|
import crypto.sha256
|
||||||
|
import freeflowuniverse.herolib.crypt.secp256k1
|
||||||
|
|
||||||
|
fn test_check() {
|
||||||
|
println('${'[+] initializing libsecp256 vlang wrapper'}')
|
||||||
|
|
||||||
|
wendy := secp256k1.new()!
|
||||||
|
webdy_priv_key := wendy.private_key_hex()
|
||||||
|
webdy_pub_key := wendy.public_key_hex()
|
||||||
|
println('-------')
|
||||||
|
println('Wendy Private: ${webdy_priv_key}')
|
||||||
|
println('Wendy Public: ${webdy_pub_key}')
|
||||||
|
println('-------')
|
||||||
|
|
||||||
|
// create 'bob' from a private key, full features will be available
|
||||||
|
bob := secp256k1.new(
|
||||||
|
privhex: '0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83'
|
||||||
|
)!
|
||||||
|
|
||||||
|
// create 'alice' from a private key, full features will be available
|
||||||
|
alice := secp256k1.new(
|
||||||
|
privhex: '0x8225825815f42e1c24a2e98714d99fee1a20b5ac864fbcb7a103cd0f37f0ffec'
|
||||||
|
)!
|
||||||
|
|
||||||
|
// create 'bobpub' from bob only public key, reduced features available (only sign check, shared keys, etc.)
|
||||||
|
bobpub := secp256k1.new(
|
||||||
|
pubhex: bob.public_key_hex()
|
||||||
|
)!
|
||||||
|
|
||||||
|
// create 'alicepub' from alice only public key, reduced features available
|
||||||
|
alicepub := secp256k1.new(
|
||||||
|
pubhex: alice.public_key_hex()
|
||||||
|
)!
|
||||||
|
|
||||||
|
shr1 := bob.sharedkeys(alice)
|
||||||
|
println('${shr1}')
|
||||||
|
|
||||||
|
shr2 := alice.sharedkeys(bob)
|
||||||
|
println('${shr2}')
|
||||||
|
|
||||||
|
// example in real world, where private key is available and only target public key
|
||||||
|
shr1pub := bob.sharedkeys(alicepub)
|
||||||
|
println('${shr1pub}')
|
||||||
|
|
||||||
|
shr2pub := alice.sharedkeys(bobpub)
|
||||||
|
println('${shr2pub}')
|
||||||
|
|
||||||
|
println('-----')
|
||||||
|
|
||||||
|
mut message := 'Hello world, this is my awesome message'
|
||||||
|
message += message
|
||||||
|
message += message
|
||||||
|
message += message
|
||||||
|
message += message
|
||||||
|
|
||||||
|
h256 := sha256.hexhash(message)
|
||||||
|
println('${h256}')
|
||||||
|
println('${h256.len}')
|
||||||
|
println('${sha256.sum(message.bytes())}')
|
||||||
|
|
||||||
|
parsed := hex.decode(h256) or { panic(err) }
|
||||||
|
println('${parsed}')
|
||||||
|
println('${parsed.len}')
|
||||||
|
|
||||||
|
//
|
||||||
|
// signature (ecdca)
|
||||||
|
//
|
||||||
|
signed := alice.sign_data(message.bytes())
|
||||||
|
println('${signed}')
|
||||||
|
|
||||||
|
signed_hex := alice.sign_data_hex(message.bytes())
|
||||||
|
println('${signed_hex}')
|
||||||
|
println('${signed_hex.len}')
|
||||||
|
|
||||||
|
signed_str := alice.sign_str(message)
|
||||||
|
println('${signed_str}')
|
||||||
|
println('${signed_str.len}')
|
||||||
|
|
||||||
|
signed_str_hex := alice.sign_str_hex(message)
|
||||||
|
assert signed_str_hex == '656699dde22d8b89d91070dee4fc8dba136172fb54e6de475024c40e4f8d5111562212c8976b5a4ccd530bdb7f40c5d9bd2cdeeec1473656566fbb9c4576ed8c'
|
||||||
|
assert signed_str_hex.len == 128
|
||||||
|
|
||||||
|
// instanciate alice with only her public key
|
||||||
|
assert alicepub.verify_data(signed, message.bytes()) == true
|
||||||
|
assert alicepub.verify_str_hex(signed_str_hex, message) == true
|
||||||
|
assert alicepub.verify_str_hex(signed_str_hex, message + 's') == false
|
||||||
|
|
||||||
|
//
|
||||||
|
// signature (schnorr)
|
||||||
|
//
|
||||||
|
// schnorr_signed := alice.schnorr_sign_data(message.bytes())
|
||||||
|
// println('${schnorr_signed}')
|
||||||
|
|
||||||
|
// schnorr_signed_hex := alice.schnorr_sign_data_hex(message.bytes())
|
||||||
|
// println('${schnorr_signed_hex}')
|
||||||
|
|
||||||
|
// schnorr_signed_str := alice.schnorr_sign_str(message)
|
||||||
|
// println('${schnorr_signed_str}')
|
||||||
|
|
||||||
|
// schnorr_signed_str_hex := alice.schnorr_sign_str_hex(message)
|
||||||
|
// println('${schnorr_signed_str_hex}')
|
||||||
|
|
||||||
|
// println('${alicepub.schnorr_verify_data(schnorr_signed, message.bytes())}')
|
||||||
|
// println('${alicepub.schnorr_verify_str(schnorr_signed_str, message)}')
|
||||||
|
|
||||||
|
// // should fails, it's not the right signature method (ecdsa / schnorr)
|
||||||
|
// println('${alicepub.verify_data(schnorr_signed, message.bytes())}')
|
||||||
|
// println('${alicepub.verify_str(schnorr_signed_str, message)}')
|
||||||
|
}
|
||||||
8
lib/crypt/secp256k1/v.mod
Normal file
8
lib/crypt/secp256k1/v.mod
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Module {
|
||||||
|
name: 'secp256k1'
|
||||||
|
description: 'secp256k1 in v'
|
||||||
|
version: '0.2.0'
|
||||||
|
license: 'MIT'
|
||||||
|
dependencies: []
|
||||||
|
}
|
||||||
|
|
||||||
21
lib/crypt/secrets/encrypt_decrypt.v
Normal file
21
lib/crypt/secrets/encrypt_decrypt.v
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module secrets
|
||||||
|
|
||||||
|
import rand
|
||||||
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
import freeflowuniverse.herolib.ui
|
||||||
|
import freeflowuniverse.herolib.crypt.aes_symmetric
|
||||||
|
import crypto.md5
|
||||||
|
import regex
|
||||||
|
import os
|
||||||
|
import encoding.base64
|
||||||
|
|
||||||
|
// will use our secret as configured for the hero to encrypt
|
||||||
|
pub fn (mut b SecretBox) encrypt(txt string) !string {
|
||||||
|
d := aes_symmetric.encrypt_str(txt, b.secret)
|
||||||
|
return base64.encode_str(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut b SecretBox) decrypt(txt string) !string {
|
||||||
|
txt2 := base64.decode_str(txt)
|
||||||
|
return aes_symmetric.decrypt_str(txt2, b.secret)
|
||||||
|
}
|
||||||
33
lib/crypt/secrets/factory.v
Normal file
33
lib/crypt/secrets/factory.v
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
module secrets
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
|
pub struct SecretBox {
|
||||||
|
pub mut:
|
||||||
|
secret string
|
||||||
|
items map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct SecretBoxArgs {
|
||||||
|
pub mut:
|
||||||
|
// reset bool
|
||||||
|
// interactive bool = true
|
||||||
|
secret string @[required]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(args SecretBoxArgs) !SecretBox {
|
||||||
|
// if args.reset {
|
||||||
|
// reset()!
|
||||||
|
// }
|
||||||
|
// if args.secret.len == 0 {
|
||||||
|
// mut myui := ui.new()!
|
||||||
|
// console.clear()
|
||||||
|
// secret_ := myui.ask_question(question: 'Please enter your hero secret string (box)')!
|
||||||
|
// secret = md5.hexhash(secret_)
|
||||||
|
// r.set(key, secret)!
|
||||||
|
// }
|
||||||
|
return SecretBox{
|
||||||
|
secret: args.secret
|
||||||
|
}
|
||||||
|
}
|
||||||
53
lib/crypt/secrets/readme.md
Normal file
53
lib/crypt/secrets/readme.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Secret Box
|
||||||
|
|
||||||
|
Some tools to work with encryption/decryption (symmetric)
|
||||||
|
|
||||||
|
```go
|
||||||
|
import freeflowuniverse.herolib.crypt.secrets
|
||||||
|
|
||||||
|
mut box:=secrets.get(secret:"mysecret")!
|
||||||
|
|
||||||
|
r:= box.encrypt("aaa")!
|
||||||
|
println(r)
|
||||||
|
assert "aaa"==box.decrypt(r)!
|
||||||
|
|
||||||
|
hex_secret:=secrets.hex_secret()!
|
||||||
|
|
||||||
|
openssl_hex_secret:=secrets.openssl_hex_secret()!
|
||||||
|
|
||||||
|
openssl_base64_secret:=secrets.openssl_base64_secret()!
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
## replace some text
|
||||||
|
|
||||||
|
some utils to manage secret keys and easily change them in text, ideal for config files.
|
||||||
|
|
||||||
|
```go
|
||||||
|
#!/usr/bin/env -S v -n -cg -w -enable-globals run
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.crypt.secrets
|
||||||
|
|
||||||
|
mut box:=secrets.get()!
|
||||||
|
box.delete("myapp.something")! //make sure we remove all previous keys
|
||||||
|
|
||||||
|
//will generate a key (hex of 24 chars) if it doesn't exist yet .
|
||||||
|
mysecret:=box.secret(key:"myapp.something.a",reset:false)!
|
||||||
|
println(mysecret)
|
||||||
|
|
||||||
|
mut test_string := "This is a test string with {ss} and {MYAPP.SOMETHING.A} and {ABC123}."
|
||||||
|
|
||||||
|
test_string1:=box.replace(txt:test_string)!
|
||||||
|
|
||||||
|
println(test_string1) -->
|
||||||
|
|
||||||
|
|
||||||
|
test_string2:=box.replace(txt:test_string,defaults:{"MYAPP.SOMETHING.A":secrets.DefaultSecretArgs{secret:"AAA"}})!
|
||||||
|
|
||||||
|
println(test_string2)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
76
lib/crypt/secrets/secrets.v
Normal file
76
lib/crypt/secrets/secrets.v
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
module secrets
|
||||||
|
|
||||||
|
import rand
|
||||||
|
// import freeflowuniverse.herolib.ui.console
|
||||||
|
// import freeflowuniverse.herolib.ui
|
||||||
|
// import freeflowuniverse.herolib.crypt.aes_symmetric
|
||||||
|
// import crypto.md5
|
||||||
|
import crypto.sha256
|
||||||
|
import os
|
||||||
|
import encoding.base64
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct SecretArgs {
|
||||||
|
pub mut:
|
||||||
|
key string @[required]
|
||||||
|
default string // if it doesn't exist yet, will create it with this value
|
||||||
|
overwrite string // will overwrite the secret with this value even if it exists
|
||||||
|
cat SecretType
|
||||||
|
// reset bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SecretType {
|
||||||
|
normal
|
||||||
|
openssl_hex
|
||||||
|
openssl_base64
|
||||||
|
}
|
||||||
|
|
||||||
|
@[params]
|
||||||
|
pub struct StringArgs {
|
||||||
|
pub:
|
||||||
|
input string
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hex_secret(args StringArgs) !string {
|
||||||
|
if args.input == '' {
|
||||||
|
// If no input string is provided, generate a random hex string
|
||||||
|
return rand.hex(24)
|
||||||
|
} else {
|
||||||
|
// If an input string is provided, use it to generate a consistent hex string
|
||||||
|
hash := sha256.sum256(args.input.bytes()).hex()
|
||||||
|
return hash[..48] // Return the first 48 characters (24 bytes) of the hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn openssl_hex_secret(args StringArgs) !string {
|
||||||
|
if args.input == '' {
|
||||||
|
// If no input string is provided, use the original openssl command
|
||||||
|
cmd := 'openssl rand -hex 32'
|
||||||
|
result := os.execute(cmd)
|
||||||
|
if result.exit_code > 0 {
|
||||||
|
return error('Command failed with exit code: ${result.exit_code} and error: ${result.output}')
|
||||||
|
}
|
||||||
|
return result.output.trim_space()
|
||||||
|
} else {
|
||||||
|
// If an input string is provided, use it to generate a consistent hash
|
||||||
|
hash := sha256.sum256(args.input.bytes()).hex()
|
||||||
|
return hash[..64] // Return the first 64 characters (32 bytes) of the hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn openssl_base64_secret(args StringArgs) !string {
|
||||||
|
if args.input == '' {
|
||||||
|
// If no input string is provided, use the original openssl command
|
||||||
|
cmd := 'openssl rand -base64 32'
|
||||||
|
result := os.execute(cmd)
|
||||||
|
if result.exit_code > 0 {
|
||||||
|
return error('Command failed with exit code: ${result.exit_code} and error: ${result.output}')
|
||||||
|
}
|
||||||
|
return result.output.trim_space()
|
||||||
|
} else {
|
||||||
|
// If an input string is provided, use it to generate a consistent base64 string
|
||||||
|
hash := sha256.sum256(args.input.bytes())
|
||||||
|
base64_str := base64.encode(hash)
|
||||||
|
return base64_str[..44] // Return the first 44 characters (32 bytes in base64)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
lib/crypt/secrets/secrets_test.v
Normal file
28
lib/crypt/secrets/secrets_test.v
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
module secrets
|
||||||
|
|
||||||
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
|
fn test_check() {
|
||||||
|
mut box := get(secret: 'mysecret')!
|
||||||
|
|
||||||
|
r := box.encrypt('aaa')!
|
||||||
|
console.print_debug(r)
|
||||||
|
assert 'aaa' == box.decrypt(r)!
|
||||||
|
|
||||||
|
hex_secret1 := hex_secret()!
|
||||||
|
console.print_debug(hex_secret1)
|
||||||
|
console.print_debug(hex_secret1.len)
|
||||||
|
assert hex_secret1.len == 24
|
||||||
|
|
||||||
|
openssl_hex_secret1 := openssl_hex_secret()!
|
||||||
|
|
||||||
|
console.print_debug(openssl_hex_secret1)
|
||||||
|
console.print_debug(openssl_hex_secret1.len)
|
||||||
|
assert openssl_hex_secret1.len == 64
|
||||||
|
|
||||||
|
openssl_base64_secret1 := openssl_base64_secret()!
|
||||||
|
|
||||||
|
console.print_debug(openssl_base64_secret1)
|
||||||
|
console.print_debug(openssl_base64_secret1.len)
|
||||||
|
assert openssl_base64_secret1.len == 44
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
module osal
|
module osal
|
||||||
|
|
||||||
import freeflowuniverse.crystallib.core.base
|
import freeflowuniverse.herolib.core.base
|
||||||
import freeflowuniverse.crystallib.data.dbfs
|
import freeflowuniverse.herolib.data.dbfs
|
||||||
import freeflowuniverse.crystallib.ui.console
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
fn donedb() !&dbfs.DB {
|
fn donedb() !&dbfs.DB {
|
||||||
mut context := base.context()!
|
mut context := base.context()!
|
||||||
|
|||||||
Reference in New Issue
Block a user