Java之Caesar与Vigenere实现

1、背景介绍

  话说目前做所谓“企业”开发的语言基本就集中在运用.Net和J2EE上了。又话说,在下很不幸又和Java“同流合污”了一把。现在回想起来,真是感慨万千啊~遥想公瑾当年,小乔初嫁了,雄姿英发,羽扇纶巾,谈笑间,强虏灰飞烟灭。~

  额,下面插播一下正题。其实,目前国内用Java做真正的“企业级”得其实并不是很多,绝大多数都是用个SSH1就觉得这就是Java之企业级开发了,之后就开始沾沾自喜了。这你说让Servlet和EJB3情何以堪啊~所以说,目前国内大多数Java的开发环境并不能说真正的武装到牙齿。

  基于这样的原因,有些时候,我们在做一些“工程”的时候~,当然对于多数情况就是IDE菜单选择“新建工程”这么个选项出来的货了,对于某些应用,需要用到一些加密算法,虽说Java自身带有专门的加密库,但是那个用起来的确有些麻烦,而且加密算法还是动态加载的,在本地测试的话问题还不是很大,痛苦的是万一到服务器上一跑,这个加密算法加载失败什么的,这可就大条了。如果说是一个什么认证系统之类的,那也就罢了。但如果只是一些对密码强要求很低,但不加密又不行的情况,那的确是挺麻烦的一件事情。

  那么,处于对易用性,易实现性的考虑,那些什么DES算法就暂时不考虑了。如果真有这个需求的话,相信找个健壮性很高的DES问题还不是很大的。而在那许多经典的加密算法中,要数Caesar加密比较经典了。所以,处于这样的一个需求,就打算实现一个经典加密算法。

  2、Caesar加密算法

  Caesar加密算法算是经典加密算法中最简单的了。对于标准的Caesar来说,就是把字母序列向后移动一定的数量,替换后得到密文,而这个数量为固定值3。也就是说,在都是由英文字母组成的文本里,字母A将会被替换成D,B会被替换成E,以此类推。

  对于Caesar加密算法,存在几点问题。首先是这个作为密钥的值是个固定的3,而且字母表又是按顺序排列的,所以只要对方知道你是用Caesar加密的,就很容易的脱密成原文,虽然有些麻烦,但是这就和用原文是差不多的,即使对加密要求很低也不能低成这样不是?然后是这个替换表,因为是基于字母表的,所以对于英文来说只能加密英文字母,这样就不能被支持了。最后,因为替换是固定的,所以,对于同一个字母,加密后的字母也是固定的。比如“AAA”这个文本加密后,就是“DDD”,看起来还不够迷惑人。

  基于以上的原因,我这里实现的Caesar做了一些修改,但是总的思路还是Caesar。

  1. public class Caesar {  
  2.     private String table;  
  3.     private int seedA = 1103515245;  
  4.     private int seedB = 12345;  
  5.       
  6.     public Caesar(String table, int seed) {  
  7.         this.table = chaos(table, seed, table.length());  
  8.     }  
  9.     public Caesar(String table) {  
  10.         this(table, 11);  
  11.     }  
  12.     public Caesar() {  
  13.         this(11);  
  14.     }  
  15.     public Caesar(int seed) {  
  16.         this("ABCDEFGHIJKLMNOPQRSTUVWXYZ", seed);  
  17.     }  
  18.     public char dict(int i, boolean reverse) {  
  19.         int s = table.length(), index = reverse ? s - i : i;  
  20.         return table.charAt(index);  
  21.     }  
  22.     public int dict(char c,  boolean reverse) {  
  23.         int s = table.length(), index = table.indexOf(c);  
  24.         return reverse ? s - index : index;  
  25.     }  
  26.     public int seed(int seed) {  
  27.         long temp = seed;  
  28.         return (int)((temp * seedA + seedB) & 0x7fffffffL);  
  29.     }  
  30.   
  31.     public String chaos(String data, int seed, int cnt) {  
  32.         StringBuffer buf = new StringBuffer(data);  
  33.         char tmp; int a, b, r = data.length();  
  34.         for (int i = 0; i < cnt; i += 1) {  
  35.             seed = seed(seed); a = seed % r;  
  36.             seed = seed(seed); b = seed % r;  
  37.             tmp = buf.charAt(a);  
  38.             buf.setCharAt(a, buf.charAt(b));  
  39.             buf.setCharAt(b, tmp);  
  40.         }  
  41.         return buf.toString();  
  42.     }  
  43.   
  44.     public String crypto(boolean reverse,  
  45.                          int key, String text) {  
  46.         String ret = null;  
  47.         StringBuilder buf = new StringBuilder();  
  48.         int m, s = table.length(), e = text.length();  
  49.   
  50.         for(int i = 0; i < e; i += 1) {  
  51.             m = dict(text.charAt(i), reverse);  
  52.             if (m < 0) break;  
  53.             m = m + key + i;  
  54.             buf.append(dict(m % s, reverse));  
  55.         }  
  56.         if (buf.length() == e)  
  57.             ret = buf.toString();  
  58.         return ret;  
  59.     }  
  60.     public String encode(int key, String text) {  
  61.         return crypto(false, key, text);  
  62.           
  63.     }  
  64.     public String decode(int key, String text) {  
  65.         return crypto(true , key, text);  
  66.     }  
  67.       
  68.     public static void main(String[] args) {  
  69.         Caesar caesar = new Caesar();  
  70.         String data = caesar.encode(32, "APPLE");  
  71.         caesar.decode(32, data);  
  72.     }  
  73. }

在上面的Caesar实现中,我用一个整数替代了原来作为密钥的固定值3。其次,可以通过传入不同的字符集让这个加密算法的适用性更广泛。最后,算法类在初始化的时候,会对替换表做一次扰乱操作,这样的话,即使是相同的替换表,因为初始化传入的seed不同,加密出来的内容也会不同。至于程序的细节,我想源码会更直观的告诉你的。

  3、Vigenere加密算法

  其实,Vigenere加密算法从历史考证来看好像并不是一个叫Vigenere的人发明的。大概只是因为某些机缘巧合,被一个叫Vigenere的人用了,并且流传开了,然后就被叫做Vigenere加密算法了。后来发现这原来是一个美丽的误解,但是既然都已经被叫习惯了,改口自然是很难了,因此就那么流传下来了。说道这里,Bellaso先生又一次的泪目了。

  为什么我这里要把Vigenere密码和Caesar放在一起呢?因为Vigenere算是一个升级版的Caesar算法。所以,当时实现了那个Caesar后,就顺带连 Bellaso 和 Vigenere 先生,也一起缅怀一下了。和Caesar相比Vigenere是一个多表替代,就是说针对明文中不同位置的字母,会选用不同的替换表来加密。如果用上面的例子来说,对于不同位置的字母,会选择不同的key去加密。说白了,就是多个Caesar叠加起来就是Vigenere。

  虽然说Vigenere在加密的效果上比Caesar有很多提升了,也弥补了Caesar上存在的一些问题。但是,我的实现还是做了一些小小的调整。

  1. public class Vigenere {  
  2.     private String table;  
  3.     private int seedA = 1103515245;  
  4.     private int seedB = 12345;  
  5.       
  6.     public Vigenere(String table, int seed) {  
  7.         this.table = chaos(table, seed, table.length());  
  8.     }  
  9.     public Vigenere(String table) {  
  10.         this(table, 11);  
  11.     }  
  12.     public Vigenere() {  
  13.         this(11);  
  14.     }  
  15.     public Vigenere(int seed) {  
  16.         this("ABCDEFGHIJKLMNOPQRSTUVWXYZ", seed);  
  17.     }  
  18.       
  19.     private char dict(int i, boolean reverse) {  
  20.         int s = table.length(), index = reverse ? s - i : i;  
  21.         return table.charAt(index);  
  22.     }  
  23.     private int dict(char c,  boolean reverse) {  
  24.         int s = table.length(), index = table.indexOf(c);  
  25.         return reverse ? s - index : index;  
  26.     }  
  27.     private int seed(int seed) {  
  28.         long temp = seed;  
  29.         return (int)((temp * seedA + seedB) & 0x7fffffffL);  
  30.     }  
  31.   
  32.     public String chaos(String data, int seed, int cnt) {  
  33.         StringBuffer buf = new StringBuffer(data);  
  34.         char tmp; int a, b, r = data.length();  
  35.         for (int i = 0; i < cnt; i += 1) {  
  36.             seed = seed(seed); a = seed % r;  
  37.             seed = seed(seed); b = seed % r;  
  38.             tmp = buf.charAt(a);  
  39.             buf.setCharAt(a, buf.charAt(b));  
  40.             buf.setCharAt(b, tmp);  
  41.         }  
  42.         return buf.toString();  
  43.     }  
  44.     public String crypto(boolean reverse,  
  45.                          String key, String text) {  
  46.         String ret = null;  
  47.         StringBuilder buf = new StringBuilder();  
  48.         int m, k, s = table.length(),   
  49.                   e = text.length(),   
  50.                   ke = key.length();  
  51.   
  52.         for(int i = 0; i < e; i += 1) {  
  53.             m = dict(text.charAt(i), reverse);  
  54.             k = dict(key.charAt(i % ke), false);  
  55.             if (m < 0 || k < 0) break;  
  56.             m = m + k + i;  
  57.             buf.append(dict(m % s, reverse));  
  58.         }  
  59.         if (buf.length() == e)  
  60.             ret = buf.toString();  
  61.         return ret;  
  62.     }  
  63.     public String encode(String key, String text) {  
  64.         return crypto(false, key, text);  
  65.           
  66.     }  
  67.     public String decode(String key, String text) {  
  68.         return crypto(true , key, text);  
  69.     }  
  70.     public static void main(String[] args) {  
  71.         Vigenere vigenere = new Vigenere();  
  72.         String data = vigenere.encode("BELLASO", "APPLE");  
  73.         vigenere.decode("BELLASO", data);  
  74.     }  
  75. }

话说,Vigenere加密算法传入的密钥到不是一个数字,是一个字符串。这个字符串中所用的字符,必须在替换表中出现过的。总的来说,Vigenere的强度要比Caesar强一些。但是终究还是会被破解的。不过,Vigenere有机会成为强度相当高的一种加密手段,前提是~前提是你的密钥长度大于或等于明文长度。然而,在实际应用中,这个密钥总是小于明文长度的。

  4、总结

  总的来说,理解这两个加密算法都不算太难。对于密码学大牛来说,这简直是小儿科了。两个算法有许多地方都是公用的,只是在一些地方有少许不同。在开发中,可以根据自己的喜好选择一下。不要期待这两个加密算法能有多大的抗破解强度,但是,作为一个烟雾弹掩盖一下明文还是可以的。不过,如果你要将这个加密算法反复对一组明文加密的话,你最好自己再测试一下。因为,加密次数多了,出来的不一定是一个强度高的密文,也可能会是明文本身,切记切记。

  另外,有些人可能会想,那如果我要加密的是中文或者二进制数据,是不是要建立一个超大的密码表,比如把中文字符集放进去?我想说的是,这个加密算法强度不是很高的,如果你非有这个需求,要上身穿着阿玛尼,脚上穿着丁子拖加裤衩,那也是可以的,方法就是用Base64把你的数据转一下码。剩下的就是传一个包含那64个字符的转换表。建议“=”符号不要加密。

  就像我题目所说的,聊胜于无。有时候,有条裤衩穿着出门,总比一丝不挂的出门要好。前者,你最多是被人说不太文明。而后者,你却铁定要被请去喝茶的。我实现这两个密码最主要的现实意义也在于此,最后,感谢你能坚持看到文章的末尾,如果你有什么疑问或者想法,希望你能告诉我,我也很乐意与你交流。

本文出自seven的测试人生公众号最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-08-31 03:28:32

Java之Caesar与Vigenere实现的相关文章

java.lang.IllegalArgumentException: Wrong FS: hdfs://localhost:54310/user/Hadoop/b, expected: file:/

java.lang.IllegalArgumentException: Wrong FS: hdfs://localhost:54310/user/Hadoop/b, expected: file:/// at org.apache.hadoop.fs.FileSystem.checkPath(FileSystem.java:410) at org.apache.hadoop.fs.RawLocalFileSystem.pathToFile(RawLocalFileSystem.java:56)

诊断 Java 代码:设计轻松的代码维护

设计 本月,Eric Allen 解释了在使代码更易于维护的同时,避免和控制无理由的变化怎么会是保持代码健壮性的关键.他集中讨论了诸如函数样式代码编写之类的概念,以及标记字段.方法和类的方法来处理并防止可变性.Eric 还解释了本任务中单元测试和重构的角色,并提供了协助实现重构的两个工具.在相关论坛中与作者和其他读者分享您对本文的看法.(您也可以单击本文顶部或底部的"讨论",访问该论坛.)有效调试源自良好的编程.设计易于维护的程序是程序员面临的最困难挑战之一,其部分原因在于程序通常并不

win7上java环境变量设置方法

  Java程序依赖JDK,就像C#程序依赖.NetFrameWork一样. 所以在开发之前,必须在win7或者是linux上,安装jdk(JavaDevelopkit)里面包括java一些工具,还有JRE(JavaRuntimeEnvironment)Java运行环境. 系统:windows7 jdk版本:jdk1.7 安装路径:c:/java 安装JDK时,上图显示的公共JRE和后续单独安装的JRE是一样的.所以只装一个就可以了. 按如上步骤操作,显示出环境变量的配置界面. 新建,添加 变量

Java新手入门教程:新手必须掌握的30条Java基本概念

  Java新手必看教程是什么?当然是绿茶小编带来的Java入门需掌握的30个基本概念啦,掌握了这些概念对于学习Java大大有利,正在学习Java编程的同学们快来看看吧. 1.OOP中唯一关系的是对象的接口是什么,就像计算机的销售商她不管电源内部结构 是怎样的,他只关系能否给你提供电就行了,也就是只要知道can or not而不是how and why.所有的程序是由一定的属性和行为对象组成的,不同的对象的访问通过函数调用来完成,对象间所有的交流都是通过方法调用,通过对封装对象数据,很大 限度上

Java有哪些常用语?Java常用语言汇总

  Java有哪些常用语?不介绍Java 常用语,对Java 的总体介绍就是不完整的.尽管促使Java 诞生的源动力是可移植性和安全性,但在Java 语言最终成型的过程中,其他一些因素也起了重要的作用.接下来,绿茶小编就一一来介绍一下. · 简单(Simple) · 安全(Secure) · 可移植(Portable) · 面向对象(Object-oriented) · 健壮(Robust) · 多线程(Multithreaded) · 体系结构中立(Architecture-neutral)

Java环境变量怎么配置?Java环境变量设置教程

  Java环境变量怎么设置?Java语言拥有跨平台的特性,它编译的程序能够运行在多种操作系统平台上,可以实现"一次编写,到处运行"的强大功能.但是Java需要自己手动配置环境变量,这对于Java新手来说是个不小的难题.接下来,小编就教大家Java环境变量设置方法. Java环境变量设置所需工具: JDK 1.7 安装包 Java环境变量设置步骤: 想要成功配置Java的环境变量,那肯定就要安装JDK,才可以开始配置. 1.安装JDK 向导进行相关参数设置.如图: 4.选择安装的路径,

java实现短地址服务

假设下面是你的视频网站链接列表,如果别人想爬取你的数据十分轻松,看规则就知道数据库是序列自增的 http://www.xxxx.com/video/1 http://www.xxxx.com/video/2 http://www.xxxx.com/video/3 那么解决这一问题,我们可以使用短地址,不对外暴露真实链接,使用对称加密是一个很好的方案. Hashids是一个很好的选择,它提供了JS/PHP/JAVA/PYTHON等编程语言的实现,这里我使用的就是它. 下面是我基于blade框架搭建

Description Resource Path Location Type Java compiler level does not match the version of the instal

Description Resource Path Location Type Java compiler level does not match the version of the instal 解决办法 在项目上右键Properties->Project Facets,在打开的Project Facets页面中的Java下拉列表中,选择相应版本. 有可能是java1.6 改成java6之类的

详解Eclipse Galileo中的快速Java编码

问题 无论您的项目或团队的规模有多大,在编辑代码库时,都会遇到如下的两 个问题: 代码模板 尽管代码模板是提高工作效率的一个理想途径,但需要确 保不能用模板来替代真正的重用,即编写方法或函数以便将它们用于许多位置.如果您有 一大段代码,那么最好在使用代码模板前先考虑采用带有变量的各种方法. 缺乏 一致性 - 当团队中的很多人编辑文件时,难免会有编码上的些许差异,但这些差 异会使代码变得难于读懂和维护.这种情况下,很难搜索到代码差异在何处发生.即便代 码是您一个人写的,如果您忘记了前面代码是如何编