1use std::convert::TryFrom;
6use std::error;
7use std::fmt;
8use std::io;
9use std::mem::size_of;
10use std::result;
11use std::slice;
12
13pub const MIN_BLOCK_SIZE: usize = 32;
14pub const MAX_BLOCK_SIZE: usize = 1 << 20;
15pub const META_SIZE: usize = size_of::<i32>() + size_of::<i64>();
16
17const BYTE: i32 = u8::MAX as i32 + 1;
18
19pub trait IntRng {
20 fn next_int(&mut self) -> i32;
21}
22
23pub trait Checksum {
24 fn reset(&mut self);
25 fn update(&mut self, v: u8);
26 fn get_value(&self) -> i64;
27}
28
29pub type Result<T> = result::Result<T, Error>;
30
31#[derive(Debug)]
32pub enum Error {
33 IoError(io::Error),
34 UnkocryptoError(Cause),
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum Cause {
39 InvalidBlockSize,
40 InvalidSourceSize,
41 InvalidDataCount,
42 InvalidData,
43 InvalidChecksum,
44}
45
46impl From<io::Error> for Error {
47 fn from(error: io::Error) -> Self {
48 Error::IoError(error)
49 }
50}
51
52impl fmt::Display for Error {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 use Error::*;
55 match self {
56 IoError(ref e) => fmt::Display::fmt(e, f),
57 UnkocryptoError(ref c) => write!(f, "UnkocryptoError({})", c),
58 }
59 }
60}
61
62impl error::Error for Error {
63 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
64 use Error::*;
65 match self {
66 IoError(ref e) => Some(e),
67 UnkocryptoError(_) => None,
68 }
69 }
70}
71
72impl fmt::Display for Cause {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 write!(f, "{:?}", self)
75 }
76}
77
78fn next_int<T: IntRng>(rng: &mut T, bound: i32) -> i32 {
80 if (bound & -bound) == bound {
81 return ((bound as u64 * (rng.next_int() as u32 >> 1) as u64) >> 31) as i32;
82 }
83 let mut val: i32;
84 loop {
85 let bits = ((rng.next_int() as u32) >> 1) as i32;
86 val = bits % bound;
87 if (bits - val).wrapping_add(bound - 1) >= 0 {
88 break;
89 }
90 }
91 val
92}
93
94fn read<R: io::Read>(src: &mut R, one_byte: &mut u8) -> Result<usize> {
95 let size = src.read(slice::from_mut(one_byte))?;
96 Ok(size)
97}
98
99fn read_int(src: &[u8], pos: usize) -> i32 {
100 let src = &src[pos..pos + size_of::<i32>()];
101 i32::from_be_bytes(TryFrom::try_from(src).unwrap())
102}
103
104fn read_long(src: &[u8], pos: usize) -> i64 {
105 let src = &src[pos..pos + size_of::<i64>()];
106 i64::from_be_bytes(TryFrom::try_from(src).unwrap())
107}
108
109fn write_int(dst: &mut [u8], pos: usize, v: i32) {
110 dst[pos..pos + size_of::<i32>()].copy_from_slice(&v.to_be_bytes());
111}
112
113fn write_long(dst: &mut [u8], pos: usize, v: i64) {
114 dst[pos..pos + size_of::<i64>()].copy_from_slice(&v.to_be_bytes());
115}
116
117pub fn decrypt<C, T, R, W>(
118 block_size: usize,
119 mut checksum: C,
120 rng: &mut T,
121 src: &mut R,
122 dst: &mut W,
123) -> Result<(u64, u64)>
124where
125 C: Checksum,
126 T: IntRng,
127 R: io::Read,
128 W: io::Write,
129{
130 if !(MIN_BLOCK_SIZE..=MAX_BLOCK_SIZE).contains(&block_size) {
131 return Err(Error::UnkocryptoError(Cause::InvalidBlockSize));
132 }
133 let data_size: usize = block_size - META_SIZE;
134 let mut mask: Vec<u8> = vec![0; block_size];
135 let mut indexes: Vec<usize> = vec![0; block_size];
136 let mut data: Vec<u8> = vec![0; block_size];
137 let mut src_size: u64 = 0;
138 let mut dst_size: u64 = 0;
139 let mut one_byte: u8 = 0;
140 let mut read_size: usize = read(src, &mut one_byte)?;
141 if read_size == 0 {
142 return Err(Error::UnkocryptoError(Cause::InvalidSourceSize));
143 }
144 while read_size > 0 {
145 for i in 0..block_size {
146 mask[i] = next_int(rng, BYTE) as u8;
147 indexes[i] = i;
148 }
149 for i in 0..block_size {
150 let j = next_int(rng, (block_size - i) as i32) as usize + i;
151 indexes.swap(i, j);
152 }
153 for j in indexes.iter() {
154 if read_size == 0 {
155 return Err(Error::UnkocryptoError(Cause::InvalidSourceSize));
156 }
157 data[*j] = one_byte ^ mask[*j];
158 read_size = read(src, &mut one_byte)?;
159 }
160 src_size += block_size as u64;
161 let count = read_int(&data, data_size);
162 let code = read_long(&data, data_size + size_of::<i32>());
163 if count < 0 || (count == 0 && read_size > 0) || data_size < count as usize {
164 return Err(Error::UnkocryptoError(Cause::InvalidDataCount));
165 }
166 let count = count as usize;
167 dst_size += count as u64;
168 checksum.reset();
169 for (i, d) in data.iter().enumerate().take(data_size) {
170 if i < count {
171 dst.write_all(slice::from_ref(d))?;
172 checksum.update(*d);
173 } else if *d != 0 {
174 return Err(Error::UnkocryptoError(Cause::InvalidData));
175 }
176 }
177 if code != checksum.get_value() {
178 return Err(Error::UnkocryptoError(Cause::InvalidChecksum));
179 }
180 }
181 Ok((src_size, dst_size))
182}
183
184pub fn encrypt<C, T, R, W>(
185 block_size: usize,
186 mut checksum: C,
187 rng: &mut T,
188 src: &mut R,
189 dst: &mut W,
190) -> Result<(u64, u64)>
191where
192 C: Checksum,
193 T: IntRng,
194 R: io::Read,
195 W: io::Write,
196{
197 if !(MIN_BLOCK_SIZE..=MAX_BLOCK_SIZE).contains(&block_size) {
198 return Err(Error::UnkocryptoError(Cause::InvalidBlockSize));
199 }
200 let data_size: usize = block_size - META_SIZE;
201 let mut data: Vec<u8> = vec![0; block_size];
202 let mut src_size: u64 = 0;
203 let mut dst_size: u64 = 0;
204 let mut one_byte: u8 = 0;
205 let mut read_size: usize = read(src, &mut one_byte)?;
206 loop {
207 dst_size += block_size as u64;
208 checksum.reset();
209 let mut count: usize = 0;
210 while count < data_size {
211 if read_size == 0 {
212 break;
213 }
214 checksum.update(one_byte);
215 data[count] = one_byte ^ next_int(rng, BYTE) as u8;
216 count += 1;
217 read_size = read(src, &mut one_byte)?;
218 }
219 src_size += count as u64;
220 for d in data.iter_mut().take(data_size).skip(count) {
221 *d = next_int(rng, BYTE) as u8;
222 }
223 write_int(&mut data, data_size, count as i32);
224 write_long(
225 &mut data,
226 data_size + size_of::<i32>(),
227 checksum.get_value(),
228 );
229 for d in data.iter_mut().skip(data_size) {
230 *d ^= next_int(rng, BYTE) as u8;
231 }
232 for i in 0..data.len() {
233 let j = next_int(rng, (data.len() - i) as i32) as usize + i;
234 data.swap(i, j);
235 }
236 dst.write_all(&data)?;
237 if read_size == 0 {
238 break;
239 }
240 }
241 Ok((src_size, dst_size))
242}
243
244pub fn calc_block_count(block_size: usize, src_len: u64) -> Result<u64> {
245 if !(MIN_BLOCK_SIZE..=MAX_BLOCK_SIZE).contains(&block_size) {
246 return Err(Error::UnkocryptoError(Cause::InvalidBlockSize));
247 }
248 let data_size: u64 = (block_size - META_SIZE) as u64;
249 let block_count: u64 = (src_len + data_size - 1) / data_size;
250 Ok(block_count)
251}
252
253pub fn calc_encrypted_size(block_size: usize, src_len: u64) -> Result<u64> {
254 calc_block_count(block_size, src_len)?
255 .checked_mul(block_size as u64)
256 .ok_or_else(|| Error::UnkocryptoError(Cause::InvalidSourceSize))
257}
258
259pub fn consume<T: IntRng>(rng: &mut T, block_size: usize, block_count: u64) -> Result<()> {
260 if !(MIN_BLOCK_SIZE..=MAX_BLOCK_SIZE).contains(&block_size) {
261 return Err(Error::UnkocryptoError(Cause::InvalidBlockSize));
262 }
263 let _ = block_count
264 .checked_mul(block_size as u64)
265 .ok_or_else(|| Error::UnkocryptoError(Cause::InvalidSourceSize))?;
266 for _ in 0..block_count {
267 for _ in 0..block_size {
268 let _ = next_int(rng, BYTE);
269 }
270 for i in 0..block_size {
271 let _ = next_int(rng, (block_size - i) as i32);
272 }
273 }
274 Ok(())
275}
276
277#[cfg(test)]
278mod tests {
279 struct JavaRandom {
280 seed: i64,
281 }
282
283 impl JavaRandom {
284 fn new(seed: i64) -> JavaRandom {
285 let mut jr = JavaRandom { seed: 0 };
286 jr.set_seed(seed);
287 jr
288 }
289
290 fn set_seed(&mut self, seed: i64) {
291 self.seed = (seed ^ 0x5DEECE66D) & ((1 << 48) - 1);
292 }
293
294 fn next(&mut self, bits: i32) -> i32 {
295 self.seed = self.seed.wrapping_mul(0x5DEECE66D).wrapping_add(0xB) & ((1 << 48) - 1);
296 (self.seed as u64 >> (48 - bits)) as i32
297 }
298 }
299
300 impl crate::IntRng for JavaRandom {
301 fn next_int(&mut self) -> i32 {
302 self.next(32)
303 }
304 }
305
306 static CRC32_TABLE: [i64; 256] = {
307 const fn f(c: i64) -> i64 {
308 (c >> 1) ^ (0xedb88320 * (c & 1))
309 }
310 const fn calc(v: i64) -> i64 {
311 f(f(f(f(f(f(f(f(v))))))))
312 }
313 let mut table = [0_i64; 256];
314 macro_rules! m {
315 ($e:expr) => {
316 table[$e] = calc($e);
317 };
318 ($e:expr, $a:expr $(,$b:expr)*) => {
319 m!(($e<<1) $(,$b)*);
320 m!((($e<<1)|1) $(,$b)*);
321 };
322 }
323 m!(0, 1, 2, 3, 4, 5, 6, 7, 8);
324 table
325 };
326
327 struct Crc32 {
328 value: i64,
329 }
330
331 impl Crc32 {
332 fn new() -> Self {
333 Self { value: 0xffffffff }
334 }
335 }
336
337 impl crate::Checksum for Crc32 {
338 fn reset(&mut self) {
339 self.value = 0xffffffff;
340 }
341
342 fn update(&mut self, v: u8) {
343 let b = CRC32_TABLE[(self.value & 0xff) as usize ^ v as usize];
344 let c = self.value >> 8;
345 self.value = b ^ c;
346 }
347
348 fn get_value(&self) -> i64 {
349 self.value ^ 0xffffffff
350 }
351 }
352
353 #[test]
354 fn it_works() {
355 let block_size: usize = crate::MIN_BLOCK_SIZE;
356
357 let seed: i64 = 123456789;
358
359 let data_src: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
360
361 let secret_src: [u8; 32] = [
362 0xa2, 0xfc, 0x45, 0x90, 0x64, 0x80, 0x77, 0x46, 0x3f, 0x7e, 0x1d, 0x7c, 0x64, 0xfe,
363 0x5c, 0x98, 0x7a, 0x00, 0x79, 0xa8, 0x64, 0xf2, 0x7d, 0xc1, 0xe3, 0x66, 0x31, 0x31,
364 0x1e, 0x62, 0xb6, 0x04,
365 ];
366
367 {
369 let crc = Crc32::new();
370
371 let mut rng = JavaRandom::new(seed);
372
373 let mut cur = secret_src.as_slice();
374
375 let mut dst = Vec::new();
376
377 let (src_len, dst_len) =
378 crate::decrypt(block_size, crc, &mut rng, &mut cur, &mut dst).unwrap();
379
380 assert_eq!(secret_src.len() as u64, src_len);
381 assert_eq!(data_src.len() as u64, dst_len);
382 assert_eq!(data_src, dst.as_ref());
383 }
384
385 {
387 let crc = Crc32::new();
388
389 let mut rng = JavaRandom::new(seed);
390
391 let mut cur = data_src.as_slice();
392
393 let mut dst = Vec::new();
394
395 let (src_len, dst_len) =
396 crate::encrypt(block_size, crc, &mut rng, &mut cur, &mut dst).unwrap();
397
398 assert_eq!(data_src.len() as u64, src_len);
399 assert_eq!(secret_src.len() as u64, dst_len);
400 assert_eq!(secret_src, dst.as_ref());
401 }
402
403 {
405 const LARGE_SRC_LEN: u64 = 12345;
406
407 let crc = Crc32::new();
408
409 let mut rng = JavaRandom::new(seed);
410
411 let mut cur = std::io::Read::take(std::io::repeat(123), LARGE_SRC_LEN);
412
413 let mut dst = std::io::sink();
414
415 let (_, len) = crate::encrypt(block_size, crc, &mut rng, &mut cur, &mut dst).unwrap();
416
417 let guess_size = crate::calc_encrypted_size(block_size, LARGE_SRC_LEN).unwrap();
418
419 assert_eq!(len, guess_size);
420 }
421
422 {
424 let multi_src: Vec<Vec<u8>> = vec![data_src.as_slice(); 5]
425 .iter()
426 .enumerate()
427 .map(|(i, a)| {
428 a.iter()
429 .map(|e| i as u8 + *e)
430 .cycle()
431 .take(10 * (i + 10))
432 .collect()
433 })
434 .collect();
435 let encrypted = {
436 let mut rng = JavaRandom::new(seed);
437 let mut dst = Vec::new();
438 for mut src in multi_src.iter().map(|a| a.as_slice()) {
439 let block_count =
440 crate::calc_block_count(block_size, src.len() as u64).unwrap();
441 dst.push(block_count as u8);
442 let crc = Crc32::new();
443 crate::encrypt(block_size, crc, &mut rng, &mut src, &mut dst).unwrap();
444 }
445 dst
446 };
447 {
448 let mut rng = JavaRandom::new(seed);
449 let mut cur = encrypted.as_slice();
450 for (i, src) in multi_src.iter().enumerate() {
451 let block_count = cur[0] as u64;
452 let size = block_size * block_count as usize;
453 cur = &cur[1..];
454 if i % 2 == 1 {
455 crate::consume(&mut rng, block_size, block_count).unwrap();
456 } else {
457 let crc = Crc32::new();
458 let mut chunk = &cur[..size];
459 let mut dst = Vec::new();
460 crate::decrypt(block_size, crc, &mut rng, &mut chunk, &mut dst).unwrap();
461 assert_eq!(src, &dst);
462 }
463 cur = &cur[size..];
464 }
465 }
466 }
467 }
468}