Simple Cipher

1. Readme

简单密码

实现一个简单的移位密码,像 Caesar 和,一个更安全的替换密码.

步骤 1

“如果他有什么秘密要说的话,他就是用密码写的,也就是说,通过改变字母表的字母顺序,一个字也说不出来。如果有人想破译这些,并理解它们的意思,他必须用字母表中的第四个字母,即 D,代替 A,以及其他的字母。 —Suetonius, Life of Julius Caesar

密码是非常直截了当的算法,使文本不可读,同时仍容易允许破译。他们容易受到许多形式的密码分析,但我们幸运的是,我们的小姐妹通常不是密码学家。

用 Caesar密码,加密来自 Julius Caesar 的消息。现在 Caesar 知道加密方式不是很好,但他还是有个好处: 几乎没有人能读对。所以对于一对夫妇的信件已经足够了,让人们无法识别他们所知道的几个字。

你的任务是创建一个简单的移位密码,就像 Caesar 密码一样。这个图像是 Caesar 密码的一个很好的例子:

Caesar Cipher

例如:

将”iamapandabear”作为输入到 encode 函数返回密码”ldpdsdqgdehdu”。(虽不足以让我们的信息在运输过程中,确保高保密性).

当将”ldpdsdqgdehdu”放入decode函数时,它将返回原始的”iamapandabear”,让您的朋友阅读您的原始消息.

步骤 2

移位密码是没有乐趣,直到你的妹妹算了出来后!尝试修改代码,允许我们指定一个密钥(key),并用作移位距离。这称为代换密码.

下面是一个例子:

给定密钥”aaaaaaaaaaaaaaaaaaa”,对字符串”iamapandabar”进行编码将返回原来的”iamapandable”.

给定密钥”ddddddddddddd”,编码我们的字符串”iamapandabore”会返回疑惑的”ldpdsdqgdhdu”.

在上面的示例中,我们为键值设置了 a=0。因此,当明文添加到密钥时,我们最终得到相同的消息。所以”aaaa”不是一个理想的密钥。但是,如果我们把密钥设置为dddd,我们将得到与 caesar 密码相同的东西.

步骤 3

任何密码中最薄弱的环节都是人。让我们通过提供随机性,并确保密钥仅包含小写字母,来使替换密码更具容错性.

如果有人根本不提交密钥,则生成一个长度至少为 100 个字符的真正随机密钥.

如果提交的密钥不只由小写字母组成,那解决方案应该以适当提醒的方式处理错误.

扩展

移位密码通过使文本略微疑惑,达到目的,但易受频率分析的影响。替换密码有助于这一点,但当密钥较短,或空格被保留时,仍然非常脆弱。稍后,你会看到一个解决这个问题的练习”crypto-square”.

如果你想在这一领域走得更远,问题引导你,走进如何以安全的方式交换密钥。看一看维基百科上的 Diffie Hellman对于该方案的最早实现之一.

资源

维基百科的替代密码http://en.wikipedia.org/wiki/Substitution_cipher

2. 开始你的表演

pub fn encode(key: &str, s: &str) -> Option<String> {
   unimplemented!("Use {} to encode {} using shift cipher", key, s)
}

pub fn decode(key: &str, s: &str) -> Option<String> {
   unimplemented!("Use {} to decode {} using shift cipher", key, s)
}

pub fn encode_random(s: &str) -> (String, String) {
   unimplemented!(
       "Generate random key with only a-z chars and encode {}. Return tuple (key, encoded s)",
       s
   )
}

3. 测试代码查看


# #![allow(unused_variables)]
#fn main() {
use std::collections::HashSet;

const PLAIN_TEXT: &str = "thisismysecret";
const KEY: &str = "abcdefghij";

#[test]
fn cipher_can_encode_with_given_key() {
   assert_eq!(encode(KEY, "aaaaaaaaaa"), Some(KEY.to_string()));
}

#[test]
//#[ignore]
fn cipher_can_decode_with_given_key() {
   assert_eq!(decode(KEY, "abcdefghij"), Some("aaaaaaaaaa".to_string()));
}

#[test]
//#[ignore]
fn cipher_is_reversible_given_key() {
   assert_eq!(
       decode(KEY, &encode(KEY, PLAIN_TEXT).unwrap()),
       Some(PLAIN_TEXT.to_string())
   );
}

#[test]
//#[ignore]
fn cipher_can_double_shift_encode() {
   let plain_text = "iamapandabear";
   assert_eq!(
       encode(plain_text, plain_text),
       Some("qayaeaagaciai".to_string())
   );
}

#[test]
//#[ignore]
fn cipher_can_wrap_encode() {
   assert_eq!(encode(KEY, "zzzzzzzzzz"), Some("zabcdefghi".to_string()));
}

#[test]
//#[ignore]
fn cipher_can_encode_a_message_that_is_shorter_than_the_key() {
   assert_eq!(encode(KEY, "aaaaa"), Some("abcde".to_string()));
}

#[test]
//#[ignore]
fn cipher_can_decode_a_message_that_is_shorter_than_the_key() {
   assert_eq!(decode(KEY, "abcde"), Some("aaaaa".to_string()));
}

#[test]
//#[ignore]
fn encode_returns_none_with_an_all_caps_key() {
   let key = "ABCDEF";
   assert_eq!(encode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn encode_returns_none_with_an_any_caps_key() {
   let key = "abcdEFg";
   assert_eq!(encode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn encode_returns_none_with_numeric_key() {
   let key = "12345";
   assert_eq!(encode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn encode_returns_none_with_any_numeric_key() {
   let key = "abcd345ef";
   assert_eq!(encode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn encode_returns_none_with_empty_key() {
   let key = "";
   assert_eq!(encode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn decode_returns_none_with_an_all_caps_key() {
   let key = "ABCDEF";
   assert_eq!(decode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn decode_returns_none_with_an_any_caps_key() {
   let key = "abcdEFg";
   assert_eq!(decode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn decode_returns_none_with_numeric_key() {
   let key = "12345";
   assert_eq!(decode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn decode_returns_none_with_any_numeric_key() {
   let key = "abcd345ef";
   assert_eq!(decode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn decode_returns_none_with_empty_key() {
   let key = "";
   assert_eq!(decode(key, PLAIN_TEXT), None);
}

#[test]
//#[ignore]
fn encode_random_uses_key_made_of_letters() {
   let (k, _) = encode_random(PLAIN_TEXT);
   assert!(k.chars().all(|c| c.is_ascii_lowercase()));
}

#[test]
//#[ignore]
fn encode_random_uses_key_of_100_characters_or_more() {
   let (k, _) = encode_random(PLAIN_TEXT);
   assert!(k.len() >= 100);
}

#[test]
//#[ignore]
fn encode_random_uses_randomly_generated_key() {
   let mut keys = HashSet::new();
   let trials = 100;
   for _ in 0..trials {
       keys.insert(encode_random(PLAIN_TEXT).0);
   }
   assert_eq!(keys.len(), trials);
}

#[test]
//#[ignore]
fn encode_random_can_encode() {
   let (k, encoded) = encode_random("aaaaaaaaaa");
   assert_eq!(encoded, k.split_at(10).0);
}

#[test]
//#[ignore]
fn encode_random_can_decode() {
   let (k, _) = encode_random("aaaaaaaaaa");
   assert_eq!(decode(&k, k.split_at(10).0), Some("aaaaaaaaaa".to_string()));
}

#[test]
//#[ignore]
fn encode_random_is_reversible() {
   let (k, encoded) = encode_random(PLAIN_TEXT);
   assert_eq!(decode(&k, &encoded), Some(PLAIN_TEXT.to_string()));
}

#}

4. 答案


# #![allow(unused_variables)]
#fn main() {
extern crate rand;
use rand::Rng;

pub fn encode_random(s: &str) -> (String, String) {
   let mut r = rand::thread_rng();
   let mut key = String::new();
   for _ in 0..100 {
       key.push(char::from('a' as u8 + r.gen_range(0, 26)));
   }
   let encoded = encode(&key, s);
   (key, encoded.unwrap())
}

pub fn encode(key: &str, s: &str) -> Option<String> {
   shift(key, s, 1)
}

pub fn decode(key: &str, s: &str) -> Option<String> {
   shift(key, s, -1)
}

fn shift(key: &str, s: &str, dir: i8) -> Option<String> {
   if key.is_empty() {
       return None;
   }
   let mut o = String::new();
   let mut i = 0;
   let mut key_arr = Vec::new();
   for c in key.chars() {
       if !c.is_ascii_lowercase() {
           return None;
       }
       key_arr.push(c);
   }
   for c in s.chars() {
       let shift = key_arr[i % key_arr.len()] as i8 - 'a' as i8;
       let n = ((c as i8 - 'a' as i8 + dir * shift) % 26 + 26) % 26;
       o.push(char::from('a' as u8 + n as u8));
       i += 1;
   }
   Some(o)
}

#}



填充/相关