Skip to content

Commit d021439

Browse files
committed
fix encoding of private keys
1 parent 45673f2 commit d021439

9 files changed

+140
-140
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ amplify = "4.6.0"
2525
strict_encoding = "2.7.0-beta.4"
2626
ascii-armor = "0.7.0"
2727
baid64 = "0.2.2"
28+
base64 = "0.22.1"
2829
secp256k1 = { version = "0.29.0", features = ["rand", "global-context", "rand-std"] }
2930
ec25519 = "0.1.0"
3031
rand = "0.8.5"

src/bip340.rs

+1-26
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,14 @@
2020
// limitations under the License.
2121

2222
use std::cmp::Ordering;
23-
use std::fmt;
24-
use std::fmt::{Display, Formatter};
2523
use std::hash::{Hash, Hasher};
26-
use std::str::FromStr;
2724

28-
use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str};
2925
use secp256k1::schnorr::Signature;
3026
use secp256k1::{Keypair, Message, SecretKey, XOnlyPublicKey, SECP256K1};
3127

3228
use crate::{Algo, Chain, InvalidPubkey, InvalidSig, SsiPub, SsiSig};
3329

34-
#[derive(Clone, Eq, PartialEq)]
30+
#[derive(Clone, Eq, PartialEq, From)]
3531
pub struct Bip340Secret(pub(crate) SecretKey);
3632

3733
impl Ord for Bip340Secret {
@@ -46,18 +42,6 @@ impl Hash for Bip340Secret {
4642
fn hash<H: Hasher>(&self, state: &mut H) { self.0.secret_bytes().hash(state) }
4743
}
4844

49-
impl DisplayBaid64 for Bip340Secret {
50-
const HRI: &'static str = "bip340-priv";
51-
const CHUNKING: bool = false;
52-
const PREFIX: bool = true;
53-
const EMBED_CHECKSUM: bool = true;
54-
const MNEMONIC: bool = false;
55-
56-
fn to_baid64_payload(&self) -> [u8; 32] { <[u8; 32]>::from(self.clone()) }
57-
}
58-
59-
impl FromBaid64Str for Bip340Secret {}
60-
6145
impl From<Bip340Secret> for [u8; 32] {
6246
fn from(ssi: Bip340Secret) -> Self { ssi.0.secret_bytes() }
6347
}
@@ -68,15 +52,6 @@ impl From<[u8; 32]> for Bip340Secret {
6852
}
6953
}
7054

71-
impl Display for Bip340Secret {
72-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) }
73-
}
74-
75-
impl FromStr for Bip340Secret {
76-
type Err = Baid64ParseError;
77-
fn from_str(s: &str) -> Result<Self, Self::Err> { Self::from_baid64_str(s) }
78-
}
79-
8055
impl Bip340Secret {
8156
pub fn new(chain: Chain) -> Self {
8257
use rand::thread_rng;

src/ed25519.rs

+1-26
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,14 @@
2020
// limitations under the License.
2121

2222
use std::cmp::Ordering;
23-
use std::fmt;
24-
use std::fmt::{Display, Formatter};
2523
use std::hash::{Hash, Hasher};
2624
use std::ops::Deref;
27-
use std::str::FromStr;
2825

29-
use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str};
3026
use ec25519::{KeyPair, Noise, PublicKey, SecretKey, Seed, Signature};
3127

3228
use crate::{Algo, Chain, InvalidPubkey, InvalidSig, SsiPub, SsiSig};
3329

34-
#[derive(Clone, Eq, PartialEq)]
30+
#[derive(Clone, Eq, PartialEq, From)]
3531
pub struct Ed25519Secret(pub(crate) SecretKey);
3632

3733
impl Ord for Ed25519Secret {
@@ -46,18 +42,6 @@ impl Hash for Ed25519Secret {
4642
fn hash<H: Hasher>(&self, state: &mut H) { self.0.as_slice().hash(state) }
4743
}
4844

49-
impl DisplayBaid64<64> for Ed25519Secret {
50-
const HRI: &'static str = "ed25519-priv";
51-
const CHUNKING: bool = false;
52-
const PREFIX: bool = true;
53-
const EMBED_CHECKSUM: bool = true;
54-
const MNEMONIC: bool = false;
55-
56-
fn to_baid64_payload(&self) -> [u8; 64] { <[u8; 64]>::from(self.clone()) }
57-
}
58-
59-
impl FromBaid64Str<64> for Ed25519Secret {}
60-
6145
impl From<Ed25519Secret> for [u8; 64] {
6246
fn from(ssi: Ed25519Secret) -> Self { *ssi.0.deref() }
6347
}
@@ -68,15 +52,6 @@ impl From<[u8; 64]> for Ed25519Secret {
6852
}
6953
}
7054

71-
impl Display for Ed25519Secret {
72-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) }
73-
}
74-
75-
impl FromStr for Ed25519Secret {
76-
type Err = Baid64ParseError;
77-
fn from_str(s: &str) -> Result<Self, Self::Err> { Self::from_baid64_str(s) }
78-
}
79-
8055
impl Ed25519Secret {
8156
pub fn new(chain: Chain) -> Self {
8257
loop {

src/encrypt.rs

+11-15
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
use std::str::FromStr;
2323

24-
use aes_gcm::aead::{Aead, OsRng};
25-
use aes_gcm::{AeadCore, Aes256Gcm, KeyInit, Nonce};
24+
use aes_gcm::aead::{Aead, Nonce, OsRng};
25+
use aes_gcm::{AeadCore, Aes256Gcm, KeyInit};
2626
use amplify::confinement::{Confined, SmallOrdMap, U64 as U64MAX};
2727
use amplify::{Bytes32, Wrapper};
2828
use armor::{ArmorHeader, ArmorParseError, AsciiArmor};
@@ -75,6 +75,7 @@ impl SymmetricKey {
7575
#[strict_type(lib = LIB_NAME_SSI)]
7676
pub struct Encrypted {
7777
pub keys: SmallOrdMap<SsiPub, Bytes32>,
78+
pub nonce: [u8; 12],
7879
pub data: Confined<Vec<u8>, 0, U64MAX>,
7980
}
8081

@@ -91,7 +92,7 @@ impl AsciiArmor for Encrypted {
9192

9293
fn to_ascii_armored_data(&self) -> Vec<u8> {
9394
self.to_strict_serialized::<U64MAX>()
94-
.expect("64 bits will not error")
95+
.expect("64 bits will never error")
9596
.into_inner()
9697
}
9798

@@ -122,9 +123,10 @@ impl Encrypted {
122123
.map_err(|_| EncryptionError::InvalidPubkey(pk))?,
123124
);
124125
}
125-
let msg = encrypt(source, key);
126+
let (nonce, msg) = encrypt(source, key);
126127
Ok(Self {
127128
keys: Confined::try_from(keys).map_err(|_| EncryptionError::TooManyReceivers)?,
129+
nonce: nonce.into(),
128130
data: Confined::from_collection_unsafe(msg),
129131
})
130132
}
@@ -140,7 +142,7 @@ impl Encrypted {
140142
let key = pair
141143
.decrypt_key(key)
142144
.map_err(|_| DecryptionError::InvalidPubkey(pair.pk))?;
143-
Ok(decrypt(self.data.to_inner(), key))
145+
Ok(decrypt(self.data.as_slice(), self.nonce.into(), key))
144146
}
145147
}
146148

@@ -179,7 +181,7 @@ impl SsiPair {
179181
}
180182
}
181183

182-
pub fn encrypt(source: Vec<u8>, key: impl AsRef<[u8]>) -> Vec<u8> {
184+
pub fn encrypt(source: Vec<u8>, key: impl AsRef<[u8]>) -> (Nonce<Aes256Gcm>, Vec<u8>) {
183185
let key = Sha256::digest(key.as_ref());
184186
let key = aes_gcm::Key::<Aes256Gcm>::from_slice(key.as_slice());
185187

@@ -189,23 +191,17 @@ pub fn encrypt(source: Vec<u8>, key: impl AsRef<[u8]>) -> Vec<u8> {
189191
let ciphered_data = cipher
190192
.encrypt(&nonce, source.as_ref())
191193
.expect("failed to encrypt");
192-
// combining nonce and encrypted data together
193-
// for storage purpose
194-
let mut encrypted_data: Vec<u8> = nonce.to_vec();
195-
encrypted_data.extend_from_slice(&ciphered_data);
196194

197-
encrypted_data
195+
(nonce, ciphered_data)
198196
}
199197

200-
pub fn decrypt(encrypted: Vec<u8>, key: impl AsRef<[u8]>) -> Vec<u8> {
198+
pub fn decrypt(encrypted: &[u8], nonce: Nonce<Aes256Gcm>, key: impl AsRef<[u8]>) -> Vec<u8> {
201199
let key = Sha256::digest(key.as_ref());
202200
let key = aes_gcm::Key::<Aes256Gcm>::from_slice(key.as_slice());
203201

204-
let (nonce_arr, ciphered_data) = encrypted.split_at(12);
205-
let nonce = Nonce::from_slice(nonce_arr);
206202
let cipher = Aes256Gcm::new(key);
207203

208204
cipher
209-
.decrypt(nonce, ciphered_data)
205+
.decrypt(&nonce, encrypted)
210206
.expect("failed to decrypt data")
211207
}

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ pub use public::{
4242
SsiSig, UnknownAlgo, UnknownChain, VerifyError,
4343
};
4444
pub use runtime::{LoadError, SignerError, SsiRuntime, SSI_DIR};
45-
pub use secret::{SecretParseError, SsiPair, SsiSecret};
45+
pub use secret::{EncryptedSecret, RevealError, SecretParseError, SsiPair, SsiSecret};
4646

4747
pub const LIB_NAME_SSI: &str = "SSI";

src/main.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -252,19 +252,15 @@ fn exec(command: Command) -> Result<(), CliError> {
252252
.map_err(CliError::Password)?;
253253

254254
eprintln!("Generating new {algo} identity....");
255-
let mut secret = match prefix {
255+
let secret = match prefix {
256256
Some(prefix) => SsiSecret::vanity(&prefix, algo, chain, threads),
257257
None => SsiSecret::new(algo, chain),
258258
};
259259

260260
let ssi = Ssi::new(uids, expiry, &secret);
261261
println!("{ssi}");
262262

263-
if !passwd.is_empty() {
264-
secret.conceal(passwd);
265-
}
266-
267-
runtime.secrets.insert(secret);
263+
runtime.secrets.insert(secret.conceal(passwd));
268264
runtime.identities.insert(ssi);
269265

270266
runtime.store().map_err(CliError::Store)?;

src/runtime.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ use std::path::PathBuf;
2929

3030
use baid64::Baid64ParseError;
3131

32-
use crate::{Fingerprint, SecretParseError, Ssi, SsiPair, SsiParseError, SsiQuery, SsiSecret};
32+
use crate::{
33+
EncryptedSecret, Fingerprint, SecretParseError, Ssi, SsiPair, SsiParseError, SsiQuery,
34+
};
3335

3436
#[derive(Debug, Display, Error, From)]
3537
#[display(inner)]
@@ -57,7 +59,7 @@ pub enum SignerError {
5759
}
5860

5961
pub struct SsiRuntime {
60-
pub secrets: BTreeSet<SsiSecret>,
62+
pub secrets: BTreeSet<EncryptedSecret>,
6163
pub identities: BTreeSet<Ssi>,
6264
}
6365

@@ -156,12 +158,9 @@ impl SsiRuntime {
156158
.secrets
157159
.iter()
158160
.find_map(|s| {
159-
let mut s = (*s).clone();
160-
if !passwd.is_empty() {
161-
s.reveal(passwd);
162-
}
163-
if s.to_public() == ssi.pk {
164-
Some(s)
161+
let sk = s.reveal(passwd).ok()?;
162+
if sk.to_public() == ssi.pk {
163+
Some(sk)
165164
} else {
166165
None
167166
}
@@ -170,7 +169,5 @@ impl SsiRuntime {
170169
Ok(SsiPair::new(ssi, sk))
171170
}
172171

173-
pub fn is_signing(&self, fp: Fingerprint) -> bool {
174-
self.secrets.iter().any(|s| s.fingerprint() == fp)
175-
}
172+
pub fn is_signing(&self, fp: Fingerprint) -> bool { self.secrets.iter().any(|s| s.fp == fp) }
176173
}

0 commit comments

Comments
 (0)