Compare commits

...

7 commits
v0.3.0 ... main

Author SHA1 Message Date
asonix 5fb8c845de Update license, repo URL 2023-04-27 19:06:10 -05:00
asonix 0df2cc3c1a Update RSA 2023-04-27 19:02:30 -05:00
asonix a871b0ae82 Bump version 2023-01-23 08:43:38 -06:00
asonix 6c43f9533c Update RSA, base64 2023-01-23 08:43:26 -06:00
asonix a0052b50e2 Update RSA 2022-10-29 11:45:48 -05:00
Aode (lion) 762872e841 Update rsa 2022-04-08 17:29:57 -05:00
asonix 3cf9079878 Update to latest RSA 2021-08-01 15:08:54 -05:00
7 changed files with 735 additions and 405 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
/target
**/*.rs.bk
Cargo.lock
/.direnv
/.envrc

View file

@ -1,19 +1,19 @@
[package]
name = "rsa-magic-public-key"
description = "Converting between the Magic Public Key format and a RustCrypto RSA type"
version = "0.3.0"
license-file = "LICENSE"
version = "0.8.0"
license = "AGPL-3.0"
authors = ["asonix <asonix@asonix.dog>"]
edition = "2018"
repository = "https://git.asonix.dog/Aardwolf/rsa-magic-public-key"
repository = "https://git.asonix.dog/asonix/rsa-magic-public-key"
readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
base64 = "0.13"
num-bigint-dig = "0.7"
rsa = "0.4.0"
base64 = "0.21"
num-bigint-dig = "0.8"
rsa = "0.9.0"
thiserror = "1.0.9"
[dev-dependencies]

968
LICENSE

File diff suppressed because it is too large Load diff

View file

@ -16,16 +16,14 @@ assert!(res.is_ok());
```
### Contributing
Unless otherwise stated, all contributions to this project will be licensed under the CSL with
the exceptions listed in the License section of this file.
Feel free to open issues for anything you find an issue with. Please note that any contributed code will be licensed under the AGPLv3.
### License
This work is licensed under the Cooperative Software License. This is not a Free Software
License, but may be considered a "source-available License." For most hobbyists, self-employed
developers, worker-owned companies, and cooperatives, this software can be used in most
projects so long as this software is distributed under the terms of the CSL. For more
information, see the provided LICENSE file. If none exists, the license can be found online
[here](https://lynnesbian.space/csl/). If you are a free software project and wish to use this
software under the terms of the GNU Affero General Public License, please contact me at
[asonix@asonix.dog](mailto:asonix@asonix.dog) and we can sort that out. If you wish to use this
project under any other license, especially in proprietary software, the answer is likely no.
Copyright © 2023 Riley Trautman
rsa-magic-public-key is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
rsa-magic-public-key is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. This file is part of rsa-magic-public-key.
You should have received a copy of the GNU General Public License along with rsa-magic-public-key. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).

61
flake.lock Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1682526928,
"narHash": "sha256-2cKh4O6t1rQ8Ok+v16URynmb0rV7oZPEbXkU0owNLQs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d6b863fd9b7bb962e6f9fdf292419a775e772891",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

25
flake.nix Normal file
View file

@ -0,0 +1,25 @@
{
description = "rsa-magic-public-key";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
};
in
{
packages.default = pkgs.hello;
devShell = with pkgs; mkShell {
nativeBuildInputs = [ cargo cargo-outdated cargo-zigbuild clippy gcc protobuf rust-analyzer rustc rustfmt ];
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
};
});
}

View file

@ -1,4 +1,4 @@
//! Encode RSA's Public Key as a Magic Public Key
//! Encode Rsa's Public Key as a Magic Public Key
//!
//! This implementation has been reverse-engineered from Mastodon's implementation, since no
//! documentation for the Magic Public Key format could be found online (Maybe I didn't look hard
@ -8,14 +8,14 @@
//! From private key
//! ```rust
//! # let mut rng = rand::thread_rng();
//! # let private_key = rsa::RSAPrivateKey::new(&mut rng, 2048).unwrap();
//! # let private_key = rsa::RsaPrivateKey::new(&mut rng, 2048).unwrap();
//! use rsa_magic_public_key::AsMagicPublicKey;
//! let string = private_key.as_magic_public_key();
//! ```
//! From public key
//! ```rust
//! # let mut rng = rand::thread_rng();
//! # let private_key = rsa::RSAPrivateKey::new(&mut rng, 2048).unwrap();
//! # let private_key = rsa::RsaPrivateKey::new(&mut rng, 2048).unwrap();
//! # let public_key = private_key.to_public_key();
//! use rsa_magic_public_key::AsMagicPublicKey;
//! let string = public_key.as_magic_public_key();
@ -24,24 +24,24 @@
//! ```rust
//! # use rsa_magic_public_key::AsMagicPublicKey;
//! # let mut rng = rand::thread_rng();
//! # let private_key = rsa::RSAPrivateKey::new(&mut rng, 2048).unwrap();
//! # let private_key = rsa::RsaPrivateKey::new(&mut rng, 2048).unwrap();
//! # let magic_public_key = private_key.as_magic_public_key();
//! use rsa::RSAPublicKey;
//! use rsa::RsaPublicKey;
//! use rsa_magic_public_key::FromMagicPublicKey;
//! let public_key = RSAPublicKey::from_magic_public_key(&magic_public_key).unwrap();
//! let public_key = RsaPublicKey::from_magic_public_key(&magic_public_key).unwrap();
//! ```
use base64::{decode_config, encode_config, URL_SAFE};
use base64::{engine::general_purpose::URL_SAFE, Engine};
use num_bigint_dig::BigUint;
use rsa::{PublicKey, RSAPublicKey};
use rsa::{traits::PublicKeyParts, RsaPublicKey};
use thiserror::Error;
/// Helper trait to add functionality to RSA types
/// Helper trait to add functionality to Rsa types
pub trait AsMagicPublicKey {
/// Produce a magic-public-key formatted string
fn as_magic_public_key(&self) -> String;
}
/// Helper trait to add functionality to RSA types
/// Helper trait to add functionality to Rsa types
pub trait FromMagicPublicKey {
/// Parse a type from a magic-public-key formatted string
fn from_magic_public_key(magic_public_key: &str) -> Result<Self, KeyError>
@ -56,43 +56,43 @@ pub enum KeyError {
#[error("The provided key is malformed")]
Malformed,
/// The magic-public-key is not RSA
/// The magic-public-key is not Rsa
#[error("The provided key is of the wrong kind")]
Kind,
}
impl<T> AsMagicPublicKey for T
where
T: PublicKey,
T: PublicKeyParts,
{
fn as_magic_public_key(&self) -> String {
let n = encode_config(&self.n().to_bytes_be(), URL_SAFE);
let e = encode_config(&self.e().to_bytes_be(), URL_SAFE);
let n = URL_SAFE.encode(&self.n().to_bytes_be());
let e = URL_SAFE.encode(&self.e().to_bytes_be());
format!("RSA.{}.{}", n, e)
format!("Rsa.{}.{}", n, e)
}
}
impl FromMagicPublicKey for RSAPublicKey {
impl FromMagicPublicKey for RsaPublicKey {
fn from_magic_public_key(magic_public_key: &str) -> Result<Self, KeyError> {
let mut iter = magic_public_key.split('.');
let kind = iter.next().ok_or(KeyError::Malformed)?;
match kind {
"RSA" => (),
"Rsa" => (),
_ => return Err(KeyError::Kind),
};
let n = iter.next().ok_or(KeyError::Malformed)?;
let e = iter.next().ok_or(KeyError::Malformed)?;
let n = decode_config(n, URL_SAFE)?;
let e = decode_config(e, URL_SAFE)?;
let n = URL_SAFE.decode(n)?;
let e = URL_SAFE.decode(e)?;
let n = BigUint::from_bytes_be(&n);
let e = BigUint::from_bytes_be(&e);
RSAPublicKey::new(n, e).map_err(|_| KeyError::Malformed)
RsaPublicKey::new(n, e).map_err(|_| KeyError::Malformed)
}
}
@ -105,32 +105,32 @@ impl From<base64::DecodeError> for KeyError {
#[cfg(test)]
mod tests {
use crate::{AsMagicPublicKey, FromMagicPublicKey};
use rsa::{RSAPrivateKey, RSAPublicKey};
use rsa::{RsaPrivateKey, RsaPublicKey};
#[test]
fn can_complete_cycle() {
let mut rng = rand::thread_rng();
let rsa = RSAPrivateKey::new(&mut rng, 2048).unwrap();
let rsa = RsaPrivateKey::new(&mut rng, 2048).unwrap();
let string = rsa.as_magic_public_key();
let res = RSAPublicKey::from_magic_public_key(&string);
let res = RsaPublicKey::from_magic_public_key(&string);
assert!(res.is_ok());
}
#[test]
fn asonix_key_is_valid() {
key_is_valid("RSA.wEvEsHqM3twoC2F3KYMQ9YOialfVQX4StkLvhLUwFv8qpmY7ZSHHl2TWpnzlo5iWS5Pi2vC41HUGYz9XT5G74IUOyuIkjTL1FIcPJDcUFCzQjN3QZcHLPJPJVNOOOEiOk8__paOyrqJTq9ikcJDMJ8KTWQgk1leOxUVEN5uaQ-p9IBFbXC76-RqabfEoqLZagVMDSOfeC2uR9xZ1q5HkFveRTGs84QLR7FJVvx078nszx4UQGnmP0M-0sOeRJGK17IoJmhaok1XBpP6XFQ45vYeIRiaFj0Pc9GNISCW70dVXKMhv-K07orQJm6PwP8USyhq4tLkq6tcPbGRqEk3ZXw==.AQAB");
key_is_valid("Rsa.wEvEsHqM3twoC2F3KYMQ9YOialfVQX4StkLvhLUwFv8qpmY7ZSHHl2TWpnzlo5iWS5Pi2vC41HUGYz9XT5G74IUOyuIkjTL1FIcPJDcUFCzQjN3QZcHLPJPJVNOOOEiOk8__paOyrqJTq9ikcJDMJ8KTWQgk1leOxUVEN5uaQ-p9IBFbXC76-RqabfEoqLZagVMDSOfeC2uR9xZ1q5HkFveRTGs84QLR7FJVvx078nszx4UQGnmP0M-0sOeRJGK17IoJmhaok1XBpP6XFQ45vYeIRiaFj0Pc9GNISCW70dVXKMhv-K07orQJm6PwP8USyhq4tLkq6tcPbGRqEk3ZXw==.AQAB");
}
#[test]
fn sir_boops_key_is_valid() {
key_is_valid("RSA.vwDujxmxoYHs64MyVB3LG5ZyBxV3ufaMRBFu42bkcTpISq1WwZ-3Zb6CI8zOO-nM-Q2llrVRYjZa4ZFnOLvMTq_Kf-Zf5wy2aCRer88gX-MsJOAtItSi412y0a_rKOuFaDYLOLeTkRvmGLgZWbsrZJOp-YWb3zQ5qsIOInkc5BwI172tMsGeFtsnbNApPV4lrmtTGaJ8RiM8MR7XANBOfOHggSt1-eAIKGIsCmINEMzs1mG9D75xKtC_sM8GfbvBclQcBstGkHAEj1VHPW0ch6Bok5_QQppicyb8UA1PAA9bznSFtKlYE4xCH8rlCDSDTBRtdnBWHKcj619Ujz4Qaw==.AQAB");
key_is_valid("Rsa.vwDujxmxoYHs64MyVB3LG5ZyBxV3ufaMRBFu42bkcTpISq1WwZ-3Zb6CI8zOO-nM-Q2llrVRYjZa4ZFnOLvMTq_Kf-Zf5wy2aCRer88gX-MsJOAtItSi412y0a_rKOuFaDYLOLeTkRvmGLgZWbsrZJOp-YWb3zQ5qsIOInkc5BwI172tMsGeFtsnbNApPV4lrmtTGaJ8RiM8MR7XANBOfOHggSt1-eAIKGIsCmINEMzs1mG9D75xKtC_sM8GfbvBclQcBstGkHAEj1VHPW0ch6Bok5_QQppicyb8UA1PAA9bznSFtKlYE4xCH8rlCDSDTBRtdnBWHKcj619Ujz4Qaw==.AQAB");
}
fn key_is_valid(key: &str) {
let res = RSAPublicKey::from_magic_public_key(key);
let res = RsaPublicKey::from_magic_public_key(key);
assert!(res.is_ok());