mirror of
https://github.com/kunkunsh/kunkun.git
synced 2025-04-20 21:49:16 +00:00

* feat: implement a file streamer for file share Only server with hardcoded file path * bump valibot version * feat: add server-info gRPC module to serve server info * feat: add ssl cert and public key to peers state When peer is online, KK always have know its cert and pub key for future secure communication * feat: add grpc ts package * Enable "/refresh-worker-extension" rest API, grpc version isn't ready yet * update pnpm lock * ci: fix CI by moving protobuf install order * ci: fix * upgrade api due to valibot incompatibility * fix: use fs instead of bun shell to be compatible with windows * skip grpc pkg build on windows * feat: local network file transfer prototype working * fix: grpc build.ts * download next to 14 * ci: add ci env try to fix next * fix: hideRefreshBtn and a few other btns' hide API in iframe ext page * feat: disable NODE_TLS_REJECT_UNAUTHORIZED for extension HMR refresh * fix: manifest json schema with objectWithRest to allow any other fields in package.json * chore: update valibot and related dependencies to version 1.0.0-beta.9 in pnpm-lock.yaml * ci: add protobuf compiler installation to manifest-schema-upload workflow * refactor: move grpc code from jarvis to a separate grpc crate for easier testing * feat(file-transfer): POC multi file + directory file transfer * feat(file-transfer): replace file transfer recursive download in ts with rust * feat(file-transfer): implement on_progress event for file transfer * feat(file-transfer): report progress every 1MB instead of 100 iterations * feat(file-transfer): add progress bar * feat(file-transfer): UI * feat(file-transfer): add file transfer bucket info preview Show total size and number of files * feat(file-transfer): improve UX Show bucket info during confirm; improve progress bar UI, prevent inconsistent width * feat(grpc): skip build in Cloudflare Pages due to missing protoc * refactor: with cargo fix, unused imports removed * ci: debug cloudflare pages env var * fix(grpc): update environment variable access for Cloudflare Pages build check * fix(grpc): add error handling for protoc command in build script * chore: update kkrpc version to 0.0.13, remove kkrpc submodule, and enhance grpc build script logging - Updated kkrpc dependency version from 0.0.12 to 0.0.13 in package.json. - Removed the kkrpc submodule from the project. - Enhanced logging in the grpc build script to include additional Cloudflare Pages environment variables for better debugging. * fix(api): typescript error, remove base.json from tsconfig * chore: update pnpm lock * fix(api): update TypeScript configuration to extend base.json and clean up unused options * refactor(api): update TypeScript configuration to extend path-alias.json and enhance compiler options * fix(api): restore KunkunManifestPermission in PermissionUnion and update valibot import in schema tests * fix: missing trait error * fix: js require replaced with import * test: fix a unit test with a more robust method --------- Co-authored-by: Huakun Shen <huaukun.shen@huakunshen.com>
138 lines
4.9 KiB
Rust
138 lines
4.9 KiB
Rust
use openssl::{
|
|
hash::MessageDigest,
|
|
pkey::{PKey, Private, Public},
|
|
rsa::Rsa,
|
|
sign::{Signer, Verifier},
|
|
};
|
|
|
|
use crate::types::Signature;
|
|
|
|
pub struct RsaCrypto {}
|
|
|
|
impl RsaCrypto {
|
|
pub fn generate_rsa() -> anyhow::Result<Rsa<Private>> {
|
|
Rsa::generate(2048).map_err(anyhow::Error::from)
|
|
}
|
|
|
|
pub fn private_key_to_public_key(private_key: &Rsa<Private>) -> Rsa<Public> {
|
|
let public_key_pem = private_key
|
|
.public_key_to_pem()
|
|
.expect("Failed to convert private key to public key");
|
|
RsaCrypto::public_key_from_pem(&public_key_pem)
|
|
.expect("Failed to convert pem to public key")
|
|
}
|
|
|
|
pub fn generate_rsa_key_pair_pem() -> anyhow::Result<(Vec<u8>, Vec<u8>)> {
|
|
let rsa = Rsa::generate(2048)?;
|
|
let private_pem = rsa.private_key_to_pem()?;
|
|
let public_pem = rsa.public_key_to_pem()?;
|
|
Ok((private_pem, public_pem))
|
|
}
|
|
|
|
pub fn private_key_from_pem(pem: &[u8]) -> anyhow::Result<Rsa<Private>> {
|
|
Rsa::private_key_from_pem(pem).map_err(anyhow::Error::from)
|
|
}
|
|
|
|
pub fn public_key_from_pem(pem: &[u8]) -> anyhow::Result<Rsa<Public>> {
|
|
Rsa::public_key_from_pem(pem).map_err(anyhow::Error::from)
|
|
}
|
|
|
|
pub fn public_key_to_string(public_key: &Rsa<Public>) -> String {
|
|
String::from_utf8(
|
|
public_key
|
|
.public_key_to_pem()
|
|
.expect("Failed to convert public key to pem"),
|
|
)
|
|
.expect("Failed to convert public key pem to string")
|
|
}
|
|
|
|
pub fn encrypt_message(public_key: &Rsa<Public>, message: &[u8]) -> anyhow::Result<Vec<u8>> {
|
|
let mut encrypted = vec![0; public_key.size() as usize];
|
|
public_key.public_encrypt(message, &mut encrypted, openssl::rsa::Padding::PKCS1)?;
|
|
Ok(encrypted)
|
|
}
|
|
|
|
pub fn decrypt_message(
|
|
private_key: &Rsa<Private>,
|
|
encrypted: &[u8],
|
|
) -> anyhow::Result<Vec<u8>> {
|
|
let mut decrypted = vec![0; private_key.size() as usize];
|
|
private_key.private_decrypt(encrypted, &mut decrypted, openssl::rsa::Padding::PKCS1)?;
|
|
Ok(decrypted)
|
|
}
|
|
pub fn sign(private_key: &Rsa<Private>, message: &[u8]) -> anyhow::Result<Vec<u8>> {
|
|
let pkey = PKey::from_rsa(private_key.clone())?;
|
|
let mut signer = Signer::new(MessageDigest::sha256(), &pkey)?;
|
|
signer.update(message)?;
|
|
let signature = signer.sign_to_vec()?;
|
|
Ok(signature)
|
|
}
|
|
|
|
pub fn verify(
|
|
public_key: &Rsa<Public>,
|
|
message: &[u8],
|
|
signature: &[u8],
|
|
) -> anyhow::Result<bool> {
|
|
let pkey = PKey::from_rsa(public_key.clone())?;
|
|
let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey)?;
|
|
verifier.update(message)?;
|
|
Ok(verifier.verify(&signature)?)
|
|
}
|
|
}
|
|
|
|
impl Signature for RsaCrypto {
|
|
fn sign_with_pem(private_pem: &[u8], message: &[u8]) -> anyhow::Result<Vec<u8>> {
|
|
let private_key = RsaCrypto::private_key_from_pem(private_pem)?;
|
|
RsaCrypto::sign(&private_key, message)
|
|
}
|
|
|
|
fn verify_with_pem(
|
|
public_pem: &[u8],
|
|
message: &[u8],
|
|
signature: &[u8],
|
|
) -> anyhow::Result<bool> {
|
|
let public_key = RsaCrypto::public_key_from_pem(public_pem)?;
|
|
RsaCrypto::verify(&public_key, message, signature)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_encrypt_decrypt() {
|
|
let rsa = RsaCrypto::generate_rsa().unwrap();
|
|
|
|
let public_key = rsa.public_key_to_pem().unwrap();
|
|
let private_key = rsa.private_key_to_pem().unwrap();
|
|
let public_rsa = RsaCrypto::public_key_from_pem(&public_key).unwrap();
|
|
let private_rsa = RsaCrypto::private_key_from_pem(&private_key).unwrap();
|
|
|
|
let encrypted = RsaCrypto::encrypt_message(&public_rsa, b"hello world").unwrap();
|
|
let decrypted = RsaCrypto::decrypt_message(&private_rsa, &encrypted).unwrap();
|
|
assert_eq!(b"hello world", &decrypted[..11]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_rsa_sign_verify() {
|
|
let (private_pem, public_pem) = RsaCrypto::generate_rsa_key_pair_pem().unwrap();
|
|
let message = b"hello world";
|
|
let private_key = RsaCrypto::private_key_from_pem(&private_pem).unwrap();
|
|
let public_key = RsaCrypto::public_key_from_pem(&public_pem).unwrap();
|
|
let signature = RsaCrypto::sign(&private_key, message).unwrap();
|
|
let verified = RsaCrypto::verify(&public_key, message, &signature).unwrap();
|
|
assert!(verified);
|
|
assert!(!RsaCrypto::verify(&public_key, b"hello world2", &signature).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn test_rsa_sign_verify_with_pem() {
|
|
let (private_pem, public_pem) = RsaCrypto::generate_rsa_key_pair_pem().unwrap();
|
|
let message = b"hello world";
|
|
let signature = RsaCrypto::sign_with_pem(&private_pem, message).unwrap();
|
|
let verified = RsaCrypto::verify_with_pem(&public_pem, message, &signature).unwrap();
|
|
assert!(verified);
|
|
}
|
|
}
|