CH-J Toolsserverihaldus üle SSH
Menüü
Avaldatud allikas

CH-J Tools

Vaata katalooge ja faile konkreetse rakenduse vabastamiseks.

Laadi alla allikas ZIP
CH-J / Server Manager 1704 failid
0.1.2-beta Lisatud: · Ehitatud:
protect.rs Lisatud: Kuupäeva ei registreerita 7,6 KB · 220 read
Kood Faili allalaadimine
1//! Historical IDEA/CFB and LibrePGP V5 secret-packet framing. V6 is untouched.
2use super::{key::Key, wire::*};
3use crate::core::error::CoreResult;
4use bytes::BytesMut;
5use pgp::{
6 crypto::{aead::AeadAlgorithm, hash::HashAlgorithm, sym::SymmetricKeyAlgorithm as Cipher},
7 ser::Serialize,
8 types::StringToKey,
9};
10use rand::RngCore;
11use subtle::ConstantTimeEq;
12use zeroize::{Zeroize, Zeroizing};
13struct WipeBuffer(BytesMut);
14impl Drop for WipeBuffer {
15 fn drop(&mut self) {
16 self.0.as_mut().zeroize();
17 }
19fn cipher(id: u8) -> CoreResult<Cipher> {
20 if ![1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13].contains(&id) {
21 return Err(invalid());
22 }
23 Ok(Cipher::from(id))
25fn s2k(reader: &mut Reader) -> CoreResult<StringToKey> {
26 let id = *reader.rest().first().ok_or_else(invalid)?;
27 let len = match id {
28 0 => 2,
29 1 => 10,
30 3 => 11,
31 _ => return Err(invalid()),
32 };
33 let bytes = reader.take(len)?;
34 if ![1, 2, 3, 8, 9, 10, 11].contains(&bytes[1]) {
35 return Err(invalid());
36 }
37 crypto(StringToKey::try_from_reader(std::io::Cursor::new(bytes)))
39fn legacy_cfb(
40 data: &[u8],
41 key: &[u8],
42 iv: &[u8],
43 algorithm: Cipher,
44 encrypt: bool,
45) -> CoreResult<Zeroizing<Vec<u8>>> {
46 let mut r = Reader::new(data);
47 let mut out = Zeroizing::new(Vec::with_capacity(data.len()));
48 let mut feedback = Zeroizing::new(iv.to_vec());
49 for _ in 0..4 {
50 let bits = r.u16()?;
51 let source = r.take((bits as usize).div_ceil(8))?;
52 let mut value = Zeroizing::new(source.to_vec());
53 if encrypt {
54 crypto(algorithm.encrypt_with_iv_regular(key, &feedback, &mut value))?;
55 } else {
56 crypto(algorithm.decrypt_with_iv_regular(key, &feedback, &mut value))?;
57 }
58 // Resynchronization aligns each MPI, retaining the last block of ciphertext.
59 let ciphertext = if encrypt { value.as_slice() } else { source };
60 let mut next = Zeroizing::new(feedback.to_vec());
61 next.extend(ciphertext);
62 let n = next.len();
63 feedback.copy_from_slice(&next[n - iv.len()..]);
64 out.extend(bits.to_be_bytes());
65 out.extend(value.as_slice());
66 }
67 r.done()?;
68 Ok(out)
70pub fn seal(key: &Key, plain: &[u8], password: &str, secret_tag: u8) -> CoreResult<Packet> {
71 let mut body = Zeroizing::new(key.public.clone());
72 if password.is_empty() {
73 body.push(0);
74 if key.version == 5 {
75 body.push(0);
76 body.extend((plain.len() as u32).to_be_bytes());
77 }
78 body.extend(plain);
79 body.extend(checksum(plain));
80 } else if key.version <= 3 {
81 let algorithm = Cipher::IDEA;
82 let derived = StringToKey::Simple {
83 hash_alg: HashAlgorithm::Md5,
84 }
85 .derive_key(password.as_bytes(), 16)
86 .map_err(|_| invalid())?;
87 let mut iv = [0u8; 8];
88 rand::thread_rng().fill_bytes(&mut iv);
89 body.push(1);
90 body.extend(iv);
91 body.extend(legacy_cfb(plain, derived.as_ref(), &iv, algorithm, true)?.as_slice());
92 body.extend(checksum(plain));
93 } else {
94 let algorithm = Cipher::AES256;
95 let mut salt = [0u8; 8];
96 rand::thread_rng().fill_bytes(&mut salt);
97 let s2k = StringToKey::IteratedAndSalted {
98 hash_alg: HashAlgorithm::Sha256,
99 salt,
100 count: 224,
101 };
102 // V5 usage 254 is the interoperable LibrePGP secret format. AES-256 CFB
103 // protects the parameter bytes and their SHA-1 integrity checksum; S2K uses SHA-256.
104 let derived = crypto(s2k.derive_key(password.as_bytes(), 32))?;
105 let mut iv = [0u8; 16];
106 rand::thread_rng().fill_bytes(&mut iv);
107 let mut encrypted = Zeroizing::new(Vec::with_capacity(plain.len() + 20));
108 encrypted.extend(plain);
109 encrypted.extend(hash(2, &[plain])?);
110 crypto(algorithm.encrypt_with_iv_regular(derived.as_ref(), &iv, &mut encrypted))?;
111 let mut parameters = vec![9];
112 parameters.extend(crypto(s2k.to_bytes())?);
113 parameters.extend(iv);
114 body.extend([254, parameters.len() as u8]);
115 body.extend(parameters);
116 body.extend((encrypted.len() as u32).to_be_bytes());
117 body.extend(encrypted.as_slice());
118 }
119 Ok(Packet {
120 tag: secret_tag,
121 body,
122 })
124pub fn open(key: &Key, password: &str) -> CoreResult<Zeroizing<Vec<u8>>> {
125 let bytes = key.secret.as_ref().ok_or_else(invalid)?;
126 let mut r = Reader::new(bytes);
127 let usage = r.u8()?;
128 if key.version <= 3 {
129 if usage == 0 {
130 if r.rest().len() < 2 {
131 return Err(invalid());
132 }
133 let n = r.rest().len() - 2;
134 let plain = r.take(n)?;
135 let expected = r.take(2)?;
136 if !bool::from(checksum(plain).ct_eq(expected)) {
137 return Err(invalid());
138 }
139 return Ok(Zeroizing::new(plain.to_vec()));
140 }
141 let algorithm = cipher(usage)?;
142 let iv = r.take(algorithm.block_size())?;
143 if r.rest().len() < 2 {
144 return Err(invalid());
145 }
146 let n = r.rest().len() - 2;
147 let encrypted = r.take(n)?;
148 let expected = r.take(2)?;
149 let derived = crypto(
150 StringToKey::Simple {
151 hash_alg: HashAlgorithm::Md5,
152 }
153 .derive_key(password.as_bytes(), algorithm.key_size()),
154 )?;
155 let plain = legacy_cfb(encrypted, derived.as_ref(), iv, algorithm, false)?;
156 if !bool::from(checksum(&plain).ct_eq(expected)) {
157 return Err(invalid());
158 }
159 return Ok(plain);
160 }
161 let count = r.u8()? as usize;
162 let mut params = Reader::new(r.take(count)?);
163 if usage == 0 {
164 params.done()?;
165 let n = r.u32()? as usize;
166 let plain = r.take(n)?;
167 let expected = r.take(2)?;
168 r.done()?;
169 if !bool::from(checksum(plain).ct_eq(expected)) {
170 return Err(invalid());
171 }
172 return Ok(Zeroizing::new(plain.to_vec()));
173 }
174 if ![253, 254].contains(&usage) {
175 return Err(invalid());
176 }
177 let algorithm = cipher(params.u8()?)?;
178 if ![Cipher::AES128, Cipher::AES192, Cipher::AES256].contains(&algorithm) {
179 return Err(invalid());
180 }
181 if usage == 253 && params.u8()? != 2 {
182 return Err(invalid());
183 }
184 let derivation = s2k(&mut params)?;
185 let iv = params.take(algorithm.block_size())?;
186 params.done()?;
187 let n = r.u32()? as usize;
188 let encrypted = r.take(n)?;
189 r.done()?;
190 let derived = crypto(derivation.derive_key(password.as_bytes(), algorithm.key_size()))?;
191 if usage == 253 {
192 if encrypted.len() < 16 || iv.len() != 16 || iv[15] != 0 {
193 return Err(invalid());
194 }
195 let mut associated = vec![0xc0 | key.tag, algorithm.into(), 2];
196 associated.extend(&key.public);
197 let mut buffer = WipeBuffer(BytesMut::with_capacity(encrypted.len()));
198 buffer.0.extend_from_slice(encrypted);
199 crypto(AeadAlgorithm::Ocb.decrypt_in_place(
200 &algorithm,
201 derived.as_ref(),
202 &iv[..15],
203 &associated,
204 &mut buffer.0,
205 ))?;
206 return Ok(Zeroizing::new(buffer.0.to_vec()));
207 }
208 let mut plain = Zeroizing::new(encrypted.to_vec());
209 crypto(algorithm.decrypt_with_iv_regular(derived.as_ref(), iv, &mut plain))?;
210 if plain.len() < 20 {
211 return Err(invalid());
212 }
213 let n = plain.len() - 20;
214 let digest = hash(2, &[&plain[..n]])?;
215 if !bool::from(digest.ct_eq(&plain[n..])) {
216 return Err(invalid());
217 }
218 plain.truncate(n);
219 Ok(plain)
SHA-256874c27ba2b17c8b68308114a2ef62d9b5876b48a0e5a1933a587a5a87a4c1333

CH-J Proprietary Software License 1.14 · Allikas on esitatud CH-J Proprietary Software License 1.14 all. Selle kättesaadavus ei muuda litsentsitingimusi ega anna täiendavaid õigusi.

Arhiiv SHA-256ac8fe790f4ba60fc098f8c985fc2656cfcc6cdc21fb34b30e308a2b54e62258f
Failid