This commit is contained in:
2024-12-25 12:38:51 +01:00
parent 4848703a8b
commit f77c7ba874
50 changed files with 3008 additions and 32 deletions

105
lib/crypt/crpgp/README.md Normal file
View 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 !

View 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
View 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
View 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
View 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
View 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
View 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
View 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
}