1use std::{1use std::{
2 env,2 env,
3 fs::{File, OpenOptions},3 fs::{File, OpenOptions},
4 io::{copy, Read, Write},4 io::{self, copy, stdin, stdout, Read, Write},
5 str::FromStr,5 str::FromStr,
6};6};
77
106 match encoding {106 match encoding {
107 OutputEncoding::Raw => coerce(w),107 OutputEncoding::Raw => coerce(w),
108 OutputEncoding::Base64 => {108 OutputEncoding::Base64 => {
109 use base64::engine::general_purpose::STANDARD;109 use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};
110
110 let writer = base64::write::EncoderWriter::new(w, &STANDARD);111 let writer = EncoderWriter::new(w, &STANDARD);
111 coerce(writer)112 coerce(writer)
112 }113 }
114 OutputEncoding::Hex => {
115 struct HexWriter<W>(W);
116 impl<W> Write for HexWriter<W>
117 where
118 W: Write,
119 {
120 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
121 let encoded = hex::encode(buf);
122 self.0.write_all(encoded.as_bytes())?;
123 Ok(buf.len())
124 }
125
126 fn flush(&mut self) -> io::Result<()> {
127 self.0.flush()
128 }
129 }
130 coerce(HexWriter(w))
131 }
113 }132 }
114}133}
115134
120 Raw,139 Raw,
121 140
122 Base64,141 Base64,
142
143 Hex,
123}144}
124145
125#[derive(Parser)]146#[derive(Parser)]
175 #[arg(long, short = 'e', value_enum, default_value_t)]196 #[arg(long, short = 'e', value_enum, default_value_t)]
176 encoding: OutputEncoding,197 encoding: OutputEncoding,
177 },198 },
199
200
201
202
203 Decode {
204 #[arg(long, short = 'i')]
205 input: String,
206 },
178 207
179 208
180 209
190219
191 match opts {220 match opts {
192 Opts::Public { output, encoding } => {221 Opts::Public { output, encoding } => {
193 write_public(&output, std::io::stdin(), encoding)?;222 write_public(&output, stdin(), encoding)?;
194 }223 }
195 Opts::Private { output, encoding } => {224 Opts::Private { output, encoding } => {
196 let recipients = load_identities()?;225 let recipients = load_identities()?;
197 write_private(&recipients, &output, std::io::stdin(), encoding)?;226 write_private(&recipients, &output, stdin(), encoding)?;
198 }227 }
199 Opts::Generate(gen) => {228 Opts::Generate(gen) => {
200 match gen {229 match gen {
204 no_embed_public,233 no_embed_public,
205 encoding,234 encoding,
206 } => {235 } => {
236 use ed25519_dalek::SigningKey;
237
207 let recipients = load_identities()?;238 let recipients = load_identities()?;
208 let key = ed25519_dalek::SigningKey::generate(&mut rng).to_keypair_bytes();239 let key = SigningKey::generate(&mut rng).to_keypair_bytes();
209 write_public(&public, &key[32..], encoding)?;240 write_public(&public, &key[32..], encoding)?;
210 write_private(241 write_private(
211 &recipients,242 &recipients,
225 private,256 private,
226 encoding,257 encoding,
227 } => {258 } => {
259 use x25519_dalek::{PublicKey, StaticSecret};
260
228 let recipients = load_identities()?;261 let recipients = load_identities()?;
229 let key = x25519_dalek::StaticSecret::random_from_rng(rng);262 let key = StaticSecret::random_from_rng(rng);
230 let public_key: x25519_dalek::PublicKey = (&key).into();263 let public_key: PublicKey = (&key).into();
231 write_public(&public, public_key.as_bytes().as_slice(), encoding)?;264 write_public(&public, public_key.as_bytes().as_slice(), encoding)?;
232 write_private(&recipients, &private, key.as_bytes().as_slice(), encoding)?;265 write_private(&recipients, &private, key.as_bytes().as_slice(), encoding)?;
233 }266 }
257 }290 }
258 }291 }
259 }292 }
293 Opts::Decode { input } => {
294 let mut data = Vec::new();
295 File::open(input)?.read_to_end(&mut data)?;
296 let data = String::from_utf8(data).context(
297 "encoded data is always utf-8, you are trying to use decode the wrong way.",
298 )?;
299 let data =
300 SecretData::from_str(&data).map_err(|e| anyhow!("failed to decode data: {e}"))?;
301 ensure!(
302 !data.encrypted,
303 "you can not decrypt secret data, only decode public."
304 );
305 stdout().write_all(&data.data)?;
306 }
260 }307 }
261 Ok(())308 Ok(())
262}309}