精华内容
下载资源
问答
  • 时间加密算法

    2012-08-15 11:12:55
    时间毫秒数及帐号为种子生成名称,可作文件名或唯一码
  • BGN是一种同态加密方案,是Boned D等人在2005提出的一种具有全同态性质的加密方案。和传统的仅能支持单同态的elgamal和paillier加密方案...BGN的实现我们主要使用JAVA中的大整数math.BigInteger类以及双线性库JPBC实现
  • 前段时间由于项目需要,使用java生成PDF文件,然后将文件压缩成ZIP格式,同时对压缩文件进行加密,先将代码及jar包上传供大家参考,并希望大家共同完善和学习。 java生成PDF,java加密压缩文件并,java生成PDF后压缩...
  • JAVA+JSP的聊天室 8个目标文件 简单 JavaScript万年历 显示出当前时间及年份,还可以选择年份及月份和日期 Java编写的HTML浏览器 一个目标文件 摘要:Java源码,网络相关,浏览器 Java编写的HTML浏览器源代码,一个很...
  • * RAS用来加密机密数据:密码/转账资金... * RAS非对唱加密Java实现: * 1.采用分组加密的方式,明文可以比较长,理论上无线长,但是太耗费时间 * 2. 不采用分组加密,直接整个元数据加密的话,每次最多加 117 bytes,
  • Java知识体系最强总结(2021版)

    万次阅读 多人点赞 2019-12-18 10:09:56
    本人从事Java开发已多年,平时有记录问题解决方案和总结知识点的习惯,整理了一些有关Java的知识体系,这不是最终版,会不定期的更新。也算是记录自己在从事编程工作的成长足迹,通过博客可以促进博主与阅读者的共同...

    更新于2021-08-13 22:55:12

    欢迎关注微信公众号【技术人成长之路】

    【技术人成长之路】,助力技术人成长!更多精彩文章第一时间在公众号发布哦!

    本人从事Java开发已多年,平时有记录问题解决方案和总结知识点的习惯,整理了一些有关Java的知识体系,这不是最终版,会不定期的更新。也算是记录自己在从事编程工作的成长足迹,通过博客可以促进博主与阅读者的共同进步,结交更多志同道合的朋友。特此分享给大家,本人见识有限,写的博客难免有错误或者疏忽的地方,还望各位大佬指点,在此表示感激不尽

    整理的Java知识体系主要包括基础知识,工具,并发编程,数据结构与算法,数据库,JVM,架构设计,应用框架,中间件,微服务架构,分布式架构,程序员的一些思考,团队与项目管理,运维,权限,推荐书籍,云计算,区块链等,包含了作为一个Java工程师在开发工作学习中需要用到或者可能用到的绝大部分知识。千里之行始于足下,希望大家根据自己的薄弱点,查缺补漏,根据自己感兴趣的方面多学习,学的精通一点,从现在开始行动起来。路漫漫其修远兮,吾将上下而求索,不管编程开发的路有多么难走,多么艰辛,我们都将百折不挠,不遗余力地去追求和探索

    文章目录

    Java面试总结

    Java面试总结汇总,整理了包括Java基础知识,集合容器,并发编程,JVM,常用开源框架Spring,MyBatis,数据库,中间件等,包含了作为一个Java工程师在面试中需要用到或者可能用到的绝大部分知识。欢迎大家阅读,本人见识有限,写的博客难免有错误或者疏忽的地方,还望各位大佬指点,在此表示感激不尽。文章持续更新中…

    序号内容链接地址
    1Java基础知识面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390612
    2Java集合容器面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588551
    3Java异常面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390689
    4并发编程面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104863992
    5JVM面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390752
    6Spring面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397516
    7Spring MVC面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397427
    8Spring Boot面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397299
    9Spring Cloud面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397367
    10MyBatis面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/101292950
    11Redis面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/103522351
    12MySQL数据库面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104778621
    13消息中间件MQ与RabbitMQ面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588612
    14Dubbo面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390006
    15Linux面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588679
    16Tomcat面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397665
    17ZooKeeper面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397719
    18Netty面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104391081
    19架构设计&分布式&数据结构与算法面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/105870730

    基础知识

    Java概述

    序号内容链接地址
    1Java简介https://thinkwon.blog.csdn.net/article/details/94353575
    2Java发展历程https://thinkwon.blog.csdn.net/article/details/94353653
    3Java语言特点https://thinkwon.blog.csdn.net/article/details/94354013
    4JDK安装与环境变量配置https://thinkwon.blog.csdn.net/article/details/94353907
    5JVM、JRE和JDK的关系https://thinkwon.blog.csdn.net/article/details/101369973
    6Java是编译型还是解释型语言https://thinkwon.blog.csdn.net/article/details/108678327

    基础语法

    大部分已完成

    待整理:

    Java开发必会的反编译知识(附支持对Lambda进行反编译的工具)

    一文读懂什么是Java中的自动拆装箱

    Java的枚举类型用法介绍

    类、枚举、接口、数组、可变参数

    泛型、序列化

    序号内容链接地址
    1Java标识符https://thinkwon.blog.csdn.net/article/details/101637454
    2Java关键字(Java 8版本)https://thinkwon.blog.csdn.net/article/details/101642385
    3Java注释https://thinkwon.blog.csdn.net/article/details/101643185
    4Java访问修饰符https://thinkwon.blog.csdn.net/article/details/101643412
    5Java分隔符https://thinkwon.blog.csdn.net/article/details/101643617
    6Java转义字符https://thinkwon.blog.csdn.net/article/details/101643769
    7Java进制https://thinkwon.blog.csdn.net/article/details/101643936
    8Java流程控制语句https://thinkwon.blog.csdn.net/article/details/101645978
    9Java流程控制语句-顺序结构https://thinkwon.blog.csdn.net/article/details/101644820
    10Java流程控制语句-分支结构https://thinkwon.blog.csdn.net/article/details/101645224
    11Java流程控制语句-循环结构https://thinkwon.blog.csdn.net/article/details/101645757
    12Java表达式https://thinkwon.blog.csdn.net/article/details/101648114
    13Java运算符https://thinkwon.blog.csdn.net/article/details/101649002
    14Java变量https://thinkwon.blog.csdn.net/article/details/101649292
    15Java常量https://thinkwon.blog.csdn.net/article/details/101649446
    16Java数据类型https://thinkwon.blog.csdn.net/article/details/101649568
    17Java反射https://thinkwon.blog.csdn.net/article/details/100128361
    18Java语法糖https://thinkwon.blog.csdn.net/article/details/100103689
    19Java注解https://thinkwon.blog.csdn.net/article/details/100178709
    20JSON简介https://thinkwon.blog.csdn.net/article/details/100642585
    21Properties类简介https://thinkwon.blog.csdn.net/article/details/100667783
    22XML简介https://thinkwon.blog.csdn.net/article/details/100642425
    23YML简介https://thinkwon.blog.csdn.net/article/details/100642870
    24Java8新特性-Lambda表达式https://thinkwon.blog.csdn.net/article/details/100642932
    25Java基础语法https://thinkwon.blog.csdn.net/article/details/94354151

    面向对象

    待整理:

    抽象

    继承、封装、多态

    接口、抽象类、内部类

    序号内容链接地址
    1什么是面向对象https://thinkwon.blog.csdn.net/article/details/100667386

    集合框架

    迭代器、增强for、泛型

    序号内容链接地址
    1Java集合框架总结https://thinkwon.blog.csdn.net/article/details/98844796
    2ArrayList(JDK1.8)源码解析https://thinkwon.blog.csdn.net/article/details/98845119
    3HashMap(JDK1.8)源码解析https://thinkwon.blog.csdn.net/article/details/98845487
    4LinkedHashMap(JDK1.8)源码解析https://thinkwon.blog.csdn.net/article/details/102574293
    5LinkedList(JDK1.8)源码解析https://thinkwon.blog.csdn.net/article/details/102573923
    6TreeMap(JDK1.8)源码解析https://thinkwon.blog.csdn.net/article/details/102571883

    IO流

    待整理:

    File、递归

    字节流、字节缓冲流

    编码表、编码方式、转换流、序列化、序列化流、打印流、commons-io

    网络编程

    网络概述、网络模型

    Socket原理机制

    UDP

    TCP/IP

    协议、OSI 七层协议、HTTP、HTTP2.0、HTTPS

    网络安全

    ​ XSS、CSRF、SQL注入、Hash Dos、脚本注入、漏洞扫描工具、验证码

    ​ DDoS防范、用户隐私信息保护、序列化漏洞

    ​ 加密解密、对称加密、哈希算法、非对称加密

    ​ 服务安全、数据安全、数据备份

    ​ 网络隔离、登录跳板机、非外网分离

    ​ 认证、授权

    常用API

    String、StringBuffer、StringBuilder、正则表达式

    Number、Radom、Math、System、包装类

    Arrays、Collections

    日期时间API

    序号内容链接地址
    1Java7日期时间APIhttps://thinkwon.blog.csdn.net/article/details/110777654
    2史上最全Java7日期时间工具类https://thinkwon.blog.csdn.net/article/details/110779441
    3Java8日期时间APIhttps://thinkwon.blog.csdn.net/article/details/111087199
    4史上最全Java8日期时间工具类https://thinkwon.blog.csdn.net/article/details/111116600

    常用工具类库

    待整理:OkHttp、commons-lang3

    序号内容链接地址
    1HttpClient工具类https://thinkwon.blog.csdn.net/article/details/101391489
    2WGS84地球坐标系,GCJ02火星坐标系,BD09百度坐标系简介与转换https://thinkwon.blog.csdn.net/article/details/101392187
    3Lombok简介、使用、工作原理、优缺点https://thinkwon.blog.csdn.net/article/details/101392808
    4Java几种常用JSON库性能比较https://thinkwon.blog.csdn.net/article/details/94354358

    单元测试

    JUnit

    异常

    序号内容链接地址
    1Java异常总结https://thinkwon.blog.csdn.net/article/details/94346911
    2Java异常架构与异常关键字https://thinkwon.blog.csdn.net/article/details/101676779
    3Java异常处理流程https://thinkwon.blog.csdn.net/article/details/101677638
    4如何选择异常类型https://thinkwon.blog.csdn.net/article/details/94346911
    5Java异常常见面试题https://thinkwon.blog.csdn.net/article/details/101681073
    6Java异常处理最佳实践https://thinkwon.blog.csdn.net/article/details/94347002

    日志

    序号内容链接地址
    1常用日志框架Log4j,Logback,Log4j2性能比较与日志门面SLF4J简介https://thinkwon.blog.csdn.net/article/details/101621135
    2日志作用https://thinkwon.blog.csdn.net/article/details/101619725
    3Apache Log4j2详解https://thinkwon.blog.csdn.net/article/details/95043111
    4Log4j2同步日志,混合日志和异步日志配置详解https://thinkwon.blog.csdn.net/article/details/101625124
    5Log4j2配置文件详解https://thinkwon.blog.csdn.net/article/details/101629302
    6Log4j2的Appenders配置详解https://thinkwon.blog.csdn.net/article/details/101625820
    7Log4j2的Filters配置详解https://thinkwon.blog.csdn.net/article/details/101627162
    8Log4j2的Policy触发策略与Strategy滚动策略配置详解https://thinkwon.blog.csdn.net/article/details/101628222
    9Log4j2的Loggers配置详解https://thinkwon.blog.csdn.net/article/details/101628736

    Java8新特性

    序号内容链接地址
    1Java8新特性-Lambda表达式https://thinkwon.blog.csdn.net/article/details/113764085
    2Java8新特性-Optionalhttps://thinkwon.blog.csdn.net/article/details/113791796
    3Java8新特性-Streamhttps://thinkwon.blog.csdn.net/article/details/113798096
    4Java8新特性-Base64https://thinkwon.blog.csdn.net/article/details/113798575
    5Java8新特性-日期时间APIhttps://thinkwon.blog.csdn.net/article/details/111087199

    工具

    IDEA

    序号内容链接地址
    1IDEA常用配置和常用插件https://thinkwon.blog.csdn.net/article/details/101020481
    2IDEA中Maven依赖下载失败解决方案https://thinkwon.blog.csdn.net/article/details/101312918
    3在IDEA中使用Linux命令https://thinkwon.blog.csdn.net/article/details/106320360

    Eclipse & STS

    序号内容链接地址
    1Eclipse & Spring Tool Suite常用配置https://thinkwon.blog.csdn.net/article/details/101025543

    Maven

    序号内容链接地址
    1Maven简介https://thinkwon.blog.csdn.net/article/details/94346090
    2Maven安装与配置https://thinkwon.blog.csdn.net/article/details/94346569
    3Maven依赖冲突https://thinkwon.blog.csdn.net/article/details/101483020
    4手动安装Maven依赖https://thinkwon.blog.csdn.net/article/details/101483478
    5Maven部署jar包到远程仓库https://thinkwon.blog.csdn.net/article/details/101483769
    6Maven私服Nexus安装与使用https://thinkwon.blog.csdn.net/article/details/94346681

    Docker

    序号内容链接地址
    1使用Docker安装GitLabhttps://thinkwon.blog.csdn.net/article/details/95042797
    2虚拟机和容器有什么不同https://thinkwon.blog.csdn.net/article/details/107476886
    3Docker 从入门到实践系列一 - 什么是Dockerhttps://thinkwon.blog.csdn.net/article/details/107477065
    4Docker 从入门到实践系列二 - Docker 安装https://thinkwon.blog.csdn.net/article/details/117638107
    5Docker 从入门到实践系列三 - Docker 常用命令https://thinkwon.blog.csdn.net/article/details/117638128
    6Docker 从入门到实践系列四 - Docker 容器编排利器 Docker Composehttps://thinkwon.blog.csdn.net/article/details/119511551

    Git

    序号内容链接地址
    1Git简介https://thinkwon.blog.csdn.net/article/details/94346816
    2版本控制https://thinkwon.blog.csdn.net/article/details/101449228
    3Git忽略文件.gitignore详解https://thinkwon.blog.csdn.net/article/details/101447866
    4Git与SVN的区别https://thinkwon.blog.csdn.net/article/details/101449611
    5常用Git命令https://thinkwon.blog.csdn.net/article/details/101450420
    6Git,GitHub与GitLab的区别https://thinkwon.blog.csdn.net/article/details/101470086

    GitLab

    GitKraken

    Navicat

    并发编程

    基础知识

    序号内容链接地址
    1并发编程的优缺点https://thinkwon.blog.csdn.net/article/details/102020811
    2线程的状态和基本操作https://thinkwon.blog.csdn.net/article/details/102027115
    3进程和线程的区别(超详细)https://thinkwon.blog.csdn.net/article/details/102021274
    4创建线程的四种方式https://thinkwon.blog.csdn.net/article/details/102021143

    并发理论

    序号内容链接地址
    1Java内存模型https://thinkwon.blog.csdn.net/article/details/102073578
    2重排序与数据依赖性https://thinkwon.blog.csdn.net/article/details/102073858
    3as-if-serial规则和happens-before规则的区别https://thinkwon.blog.csdn.net/article/details/102074107
    4Java并发理论总结https://thinkwon.blog.csdn.net/article/details/102074440

    并发关键字

    序号内容链接地址
    1Java并发关键字-synchronizedhttps://thinkwon.blog.csdn.net/article/details/102243189
    2Java并发关键字-volatilehttps://thinkwon.blog.csdn.net/article/details/102243670
    3Java并发关键字-finalhttps://thinkwon.blog.csdn.net/article/details/102244477

    Lock体系

    待整理:

    公平锁 & 非公平锁

    乐观锁 & 悲观锁

    可重入锁 & 不可重入锁

    互斥锁 & 共享锁

    死锁

    序号内容链接地址
    1Lock简介与初识AQShttps://thinkwon.blog.csdn.net/article/details/102468837
    2AQS(AbstractQueuedSynchronizer)详解与源码分析https://thinkwon.blog.csdn.net/article/details/102469112
    3ReentrantLock(重入锁)实现原理与公平锁非公平锁区别https://thinkwon.blog.csdn.net/article/details/102469388
    4读写锁ReentrantReadWriteLock源码分析https://thinkwon.blog.csdn.net/article/details/102469598
    5Condition源码分析与等待通知机制https://thinkwon.blog.csdn.net/article/details/102469889
    6LockSupport详解https://thinkwon.blog.csdn.net/article/details/102469993

    并发容器

    序号内容链接地址
    1并发容器之ConcurrentHashMap详解(JDK1.8版本)与源码分析https://thinkwon.blog.csdn.net/article/details/102506447
    2并发容器之ConcurrentLinkedQueue详解与源码分析https://thinkwon.blog.csdn.net/article/details/102508089
    3并发容器之CopyOnWriteArrayList详解https://thinkwon.blog.csdn.net/article/details/102508258
    4并发容器之ThreadLocal详解https://thinkwon.blog.csdn.net/article/details/102508381
    5ThreadLocal内存泄漏分析与解决方案https://thinkwon.blog.csdn.net/article/details/102508721
    6并发容器之BlockingQueue详解https://thinkwon.blog.csdn.net/article/details/102508901
    7并发容器之ArrayBlockingQueue与LinkedBlockingQueue详解https://thinkwon.blog.csdn.net/article/details/102508971

    线程池

    序号内容链接地址
    1线程池ThreadPoolExecutor详解https://thinkwon.blog.csdn.net/article/details/102541900
    2Executors类创建四种常见线程池https://thinkwon.blog.csdn.net/article/details/102541990
    3线程池之ScheduledThreadPoolExecutor详解https://thinkwon.blog.csdn.net/article/details/102542299
    4FutureTask详解https://thinkwon.blog.csdn.net/article/details/102542404

    原子操作类

    序号内容链接地址
    1原子操作类总结https://thinkwon.blog.csdn.net/article/details/102556910

    并发工具

    序号内容链接地址
    1并发工具之CountDownLatch与CyclicBarrierhttps://thinkwon.blog.csdn.net/article/details/102556958
    2并发工具之Semaphore与Exchangerhttps://thinkwon.blog.csdn.net/article/details/102557034

    并发实践

    序号内容链接地址
    1实现生产者消费者的三种方式https://thinkwon.blog.csdn.net/article/details/102557126

    数据结构与算法

    数据结构

    序号内容链接地址
    1红黑树详细分析(图文详解),看了都说好https://thinkwon.blog.csdn.net/article/details/102571535
    1、数组
    2、栈
    3、队列
    4、链表
    5、树
    	二叉树
        完全二叉树
        平衡二叉树
        二叉查找树(BST)
        红黑树
        B,B+,B*树
        LSM 树
    
    字段是不是数据结构
    

    算法

    语言只是编程工具,算法才是编程之魂!

    1、排序算法:快速排序、归并排序、计数排序
    2、搜索算法:回溯、递归、剪枝
    3、图论:最短路径、最小生成树、网络流建模
    4、动态规划:背包问题、最长子序列、计数问题
    5、基础技巧:分治、倍增、二分法、贪心算法
    
    宽度优先搜索
    深度优先搜索
    广度优先
    双指针
    扫描线
    
    朴素贝叶斯
    推荐算法
    

    排序算法

    序号内容链接地址
    1史上最全经典排序算法总结(Java实现)https://thinkwon.blog.csdn.net/article/details/95616819
    2冒泡排序(Bubble Sort)https://thinkwon.blog.csdn.net/article/details/101534473
    3选择排序(Selection Sort)https://thinkwon.blog.csdn.net/article/details/101534721
    4插入排序(Insertion Sort)https://thinkwon.blog.csdn.net/article/details/101537804
    5希尔排序(Shell Sort)https://thinkwon.blog.csdn.net/article/details/101538166
    6归并排序(Merge Sort)https://thinkwon.blog.csdn.net/article/details/101538756
    7快速排序(Quick Sort)https://thinkwon.blog.csdn.net/article/details/101543580
    8堆排序(Heap Sort)https://thinkwon.blog.csdn.net/article/details/101543941
    9计数排序(Counting Sort)https://thinkwon.blog.csdn.net/article/details/101544159
    10桶排序(Bucket Sort)https://thinkwon.blog.csdn.net/article/details/101544356
    11基数排序(Radix Sort)https://thinkwon.blog.csdn.net/article/details/101545529

    LeetCode

    序号内容链接地址
    1LeetCode第1题 两数之和(Two Sum)https://thinkwon.blog.csdn.net/article/details/103113049
    2LeetCode第3题 无重复字符的最长子串(Longest Substring Without Repeating Characters)https://thinkwon.blog.csdn.net/article/details/103113969
    3LeetCode第7题 整数反转(Reverse Integer)https://thinkwon.blog.csdn.net/article/details/103113167
    4LeetCode第9题 回文数(Palindrome Number)https://thinkwon.blog.csdn.net/article/details/103113151
    5LeetCode第13题 罗马数字转整数(Roman to Integer)https://thinkwon.blog.csdn.net/article/details/103113519
    6LeetCode第14题 最长公共前缀(Longest Common Prefix)https://thinkwon.blog.csdn.net/article/details/103113700
    7LeetCode第20题 有效的括号(Valid Parentheses)https://thinkwon.blog.csdn.net/article/details/103113848
    8LeetCode第26题 删除排序数组中的重复项(Remove Duplicates from Sorted Array)https://thinkwon.blog.csdn.net/article/details/103113097

    数据库

    Oracle

    MySQL

    数据库基础知识

    序号内容链接地址
    1MySQL语句分类https://thinkwon.blog.csdn.net/article/details/106610851
    2MySQL插入语句insert into,insert ignore into,insert into … on duplicate key update,replace into-解决唯一键约束https://thinkwon.blog.csdn.net/article/details/106610789
    3MySQL复制表的三种方式https://thinkwon.blog.csdn.net/article/details/106610810
    4MySQL删除表的三种方式https://thinkwon.blog.csdn.net/article/details/106610831
    5MySQL中count(字段) ,count(主键 id) ,count(1)和count(*)的区别https://thinkwon.blog.csdn.net/article/details/106610859

    数据类型

    引擎

    索引

    三大范式

    常用SQL语句

    存储过程与函数

    视图

    MySQL优化

    事务

    数据备份与还原

    Redis

    序号内容链接地址
    1Redis总结https://thinkwon.blog.csdn.net/article/details/99999584
    2Redis使用场景https://thinkwon.blog.csdn.net/article/details/101521497
    3Redis数据类型https://thinkwon.blog.csdn.net/article/details/101521724
    4Redis持久化https://thinkwon.blog.csdn.net/article/details/101522209
    5Redis过期键的删除策略https://thinkwon.blog.csdn.net/article/details/101522970
    6Redis数据淘汰策略https://thinkwon.blog.csdn.net/article/details/101530624
    7Redis与Memcached的区别https://thinkwon.blog.csdn.net/article/details/101530406
    8Redis常见面试题(精简版)https://thinkwon.blog.csdn.net/article/details/103522351
    9Redis中缓存雪崩、缓存穿透等问题的解决方案https://thinkwon.blog.csdn.net/article/details/103402008
    10阿里云Redis开发规范学习总结https://thinkwon.blog.csdn.net/article/details/103400250
    11Redis开发常用规范https://thinkwon.blog.csdn.net/article/details/103401781
    12这可能是最中肯的Redis规范了https://thinkwon.blog.csdn.net/article/details/103401978

    Java虚拟机

    深入理解Java虚拟机

    序号内容链接地址
    1深入理解Java虚拟机-走近Javahttps://thinkwon.blog.csdn.net/article/details/103804387
    2深入理解Java虚拟机-Java内存区域与内存溢出异常https://thinkwon.blog.csdn.net/article/details/103827387
    3深入理解Java虚拟机-垃圾回收器与内存分配策略https://thinkwon.blog.csdn.net/article/details/103831676
    4深入理解Java虚拟机-虚拟机执行子系统https://thinkwon.blog.csdn.net/article/details/103835168
    5深入理解Java虚拟机-程序编译与代码优化https://thinkwon.blog.csdn.net/article/details/103835883
    6深入理解Java虚拟机-高效并发https://thinkwon.blog.csdn.net/article/details/103836167

    架构设计

    高可用架构

    高并发架构

    可伸缩架构

    集群

    设计模式

    常用设计模式

    创建型:
    单例模式、工厂模式、抽象工厂模式

    结构型:
    适配器模式、外观模式、代理模式、装饰器模式

    行为型:
    观察者模式、策略模式、模板模式

    序号内容链接地址
    1设计模式https://thinkwon.blog.csdn.net/article/details/96829572

    创建型模式

    序号内容链接地址
    1抽象工厂模式https://thinkwon.blog.csdn.net/article/details/101382584
    2单例模式https://thinkwon.blog.csdn.net/article/details/101382855
    3工厂模式https://thinkwon.blog.csdn.net/article/details/101383285
    4建造者模式https://thinkwon.blog.csdn.net/article/details/101383401
    5原型模式https://thinkwon.blog.csdn.net/article/details/101383491

    结构型模式

    序号内容链接地址
    1代理模式https://thinkwon.blog.csdn.net/article/details/101384436
    2过滤器模式https://thinkwon.blog.csdn.net/article/details/101384514
    3桥接模式https://thinkwon.blog.csdn.net/article/details/101384584
    4适配器模式https://thinkwon.blog.csdn.net/article/details/101384619
    5外观模式https://thinkwon.blog.csdn.net/article/details/101384676
    6享元模式https://thinkwon.blog.csdn.net/article/details/101384716
    7装饰器模式https://thinkwon.blog.csdn.net/article/details/101384753
    8组合模式https://thinkwon.blog.csdn.net/article/details/101384786

    行为型模式

    序号内容链接地址
    1备忘录模式https://thinkwon.blog.csdn.net/article/details/101383582
    2策略模式https://thinkwon.blog.csdn.net/article/details/101383647
    3迭代器模式https://thinkwon.blog.csdn.net/article/details/101383722
    4访问者模式https://thinkwon.blog.csdn.net/article/details/101383780
    5观察者模式https://thinkwon.blog.csdn.net/article/details/101383872
    6解释器模式https://thinkwon.blog.csdn.net/article/details/101383930
    7空对象模式https://thinkwon.blog.csdn.net/article/details/101384001
    8命令模式https://thinkwon.blog.csdn.net/article/details/101384090
    9模板模式https://thinkwon.blog.csdn.net/article/details/101384138
    10责任链模式https://thinkwon.blog.csdn.net/article/details/101384195
    11中介者模式https://thinkwon.blog.csdn.net/article/details/101384251
    12状态模式https://thinkwon.blog.csdn.net/article/details/101384315

    J2EE模式

    序号内容链接地址
    1MVC模式https://thinkwon.blog.csdn.net/article/details/101381701
    2传输对象模式https://thinkwon.blog.csdn.net/article/details/101382134
    3服务定位器模式https://thinkwon.blog.csdn.net/article/details/101382179
    4拦截过滤器模式https://thinkwon.blog.csdn.net/article/details/101382210
    5前端控制器模式https://thinkwon.blog.csdn.net/article/details/101382247
    6数据访问对象模式https://thinkwon.blog.csdn.net/article/details/101382287
    7业务代表模式https://thinkwon.blog.csdn.net/article/details/101382356
    8组合实体模式https://thinkwon.blog.csdn.net/article/details/101382390

    实践应用

    序号内容链接地址
    1业务复杂=if else?刚来的大神竟然用策略+工厂彻底干掉了他们!https://thinkwon.blog.csdn.net/article/details/102924813

    应用框架

    如何学习一个框架或者技术

    • 是什么,简介,概述

    • 有什么用,用途,使用场景

    • 怎么用,在实际开发中的应用,注意事项

    • 优缺点

    • 框架原理,工作流程,工作原理

    • 常见面试题

    • 源码分析,核心类,核心方法,设计模式

    • 发布博客,在开发和实践中,博客反馈中持续改进

    • 与同事朋友交流,技术论坛,技术分享中持续丰富知识

    常用框架

    • 集成开发工具(IDE):Eclipse、MyEclipse、Spring Tool Suite(STS)、Intellij IDEA、NetBeans、JBuilder、JCreator

    • JAVA服务器:tomcat、jboss、websphere、weblogic、resin、jetty、apusic、apache

    • 负载均衡:nginx、lvs

    • web层框架:Spring MVC、Struts2、Struts1、Google Web Toolkit(GWT)、JQWEB

    • 服务层框架:Spring、EJB

    • 持久层框架:Hibernate、MyBatis、JPA、TopLink

    • 数据库:Oracle、MySql、MSSQL、Redis

    • 项目构建:maven、ant

    • 持续集成:Jenkins

    • 版本控制:SVN、CVS、VSS、GIT

    • 私服:Nexus

    • 消息组件:IBM MQ、RabbitMQ、ActiveMQ、RocketMq

    • 日志框架:Commons Logging、log4j 、slf4j、IOC

    • 缓存框架:memcache、redis、ehcache、jboss cache

    • RPC框架:Hessian、Dubbo

    • 规则引擎:Drools

    • 工作流:Activiti

    • 批处理:Spring Batch

    • 通用查询框架:Query DSL

    • JAVA安全框架:shiro、Spring Security

    • 代码静态检查工具:FindBugs、PMD

    • Linux操作系统:CentOS、Ubuntu、SUSE Linux、

    • 常用工具:PLSQL Developer(Oracle)、Navicat(MySql)、FileZilla(FTP)、Xshell(SSH)、putty(SSH)、SecureCRT(SSH)、jd-gui(反编译)

    Spring

    序号内容链接地址
    1Spring简介、设计理念、优缺点、应用场景https://thinkwon.blog.csdn.net/article/details/102810748
    2Spring模块组成(框架组成、整体架构、体系架构、体系结构)https://thinkwon.blog.csdn.net/article/details/102810819
    3Spring容器中bean的生命周期https://thinkwon.blog.csdn.net/article/details/102866432
    4控制反转(IoC)与依赖注入(DI)详解https://thinkwon.blog.csdn.net/article/details/102912332

    《Spring实战》读书笔记

    序号内容链接地址
    1《Spring实战》读书笔记-第1章 Spring之旅https://thinkwon.blog.csdn.net/article/details/103097364
    2《Spring实战》读书笔记-第2章 装配Beanhttps://thinkwon.blog.csdn.net/article/details/103527675
    3《Spring实战》读书笔记-第3章 高级装配https://thinkwon.blog.csdn.net/article/details/103536621
    4《Spring实战》读书笔记-第4章 面向切面的Springhttps://thinkwon.blog.csdn.net/article/details/103541166
    5《Spring实战》读书笔记-第5章 构建Spring Web应用程序https://thinkwon.blog.csdn.net/article/details/103550083
    6《Spring实战》读书笔记-第6章 渲染Web视图https://thinkwon.blog.csdn.net/article/details/103559672
    7《Spring实战》读书笔记-第7章 Spring MVC的高级技术https://thinkwon.blog.csdn.net/article/details/103562467

    Spring MVC

    MyBatis

    序号内容链接地址
    1MyBatis官方文档https://thinkwon.blog.csdn.net/article/details/100887995
    2MyBatis官方文档-简介https://thinkwon.blog.csdn.net/article/details/100887076
    3MyBatis官方文档-入门https://thinkwon.blog.csdn.net/article/details/100887176
    4MyBatis官方文档-XML 配置https://thinkwon.blog.csdn.net/article/details/100887349
    5MyBatis官方文档-XML 映射文件https://thinkwon.blog.csdn.net/article/details/100887478
    6MyBatis官方文档-动态 SQLhttps://thinkwon.blog.csdn.net/article/details/100887702
    7MyBatis官方文档-Java APIhttps://thinkwon.blog.csdn.net/article/details/100887746
    8MyBatis官方文档-SQL 语句构建器类https://thinkwon.blog.csdn.net/article/details/100887821
    9MyBatis官方文档-日志https://thinkwon.blog.csdn.net/article/details/100887951
    10MyBatis功能架构https://thinkwon.blog.csdn.net/article/details/101295025
    11MyBatis工作原理https://thinkwon.blog.csdn.net/article/details/101293609
    12MyBatis核心类https://thinkwon.blog.csdn.net/article/details/101293216
    13MyBatis面试宝典https://thinkwon.blog.csdn.net/article/details/101292950
    14MyBatis实现一对一,一对多关联查询https://thinkwon.blog.csdn.net/article/details/101322334
    15MyBatis缓存https://thinkwon.blog.csdn.net/article/details/101351212

    MyBatis 源码分析

    序号内容链接地址
    1MyBatis 源码分析 - MyBatis入门https://thinkwon.blog.csdn.net/article/details/114808852
    2MyBatis 源码分析 - 配置文件解析过程https://thinkwon.blog.csdn.net/article/details/114808962
    3MyBatis 源码分析 - 映射文件解析过程https://thinkwon.blog.csdn.net/article/details/115423167
    4MyBatis 源码分析 - SQL 的执行过程https://thinkwon.blog.csdn.net/article/details/115603376
    5MyBatis 源码分析 - 内置数据源https://thinkwon.blog.csdn.net/article/details/116331419
    6MyBatis 源码分析 - 缓存原理https://thinkwon.blog.csdn.net/article/details/116809942
    7MyBatis 源码分析 - 插件机制https://thinkwon.blog.csdn.net/article/details/116809961

    Quartz

    序号内容链接地址
    1Quartz简介https://thinkwon.blog.csdn.net/article/details/109936696

    Hibernate

    Shiro

    Spring Security

    Netty

    搜索引擎

    Lucene/Solr

    Elasticsearch

    ELK

    中间件

    消息中间件

    RabbitMQ

    RocketMQ

    ActiveMQ

    Kafka

    远程过程调用中间件

    Dubbo

    数据访问中间件

    Sharding JDBC

    MyCat

    Web应用服务器

    Tomcat

    待整理:Tomcat各组件作用 Tomcat集群 Tomcat面试题

    序号内容链接地址
    1Win10安装Tomcat服务器与配置环境变量https://thinkwon.blog.csdn.net/article/details/102622905
    2Linux(CentOS7)安装Tomcat与设置Tomcat为开机启动项https://thinkwon.blog.csdn.net/article/details/102717537
    3Tomcat与JDK版本对应关系,Tomcat各版本特性https://thinkwon.blog.csdn.net/article/details/102622738
    4Tomcat目录结构https://thinkwon.blog.csdn.net/article/details/102619466
    5Tomcat乱码与端口占用的解决方案https://thinkwon.blog.csdn.net/article/details/102622824
    6Tomcat系统架构与请求处理流程https://thinkwon.blog.csdn.net/article/details/102676442
    7史上最强Tomcat8性能优化https://thinkwon.blog.csdn.net/article/details/102744033

    Nginx

    缓存

    本地缓存

    客户端缓存

    服务端缓存

    ​ web缓存,Redis,Memcached,Ehcache

    其他

    Zookeeper

    微服务与分布式

    Spring Boot

    序号内容链接地址
    1application.yml与bootstrap.yml的区别https://thinkwon.blog.csdn.net/article/details/100007093
    2一分钟了解约定优于配置https://thinkwon.blog.csdn.net/article/details/101703815

    Spring Cloud

    序号内容链接地址
    1Spring Cloud入门-十分钟了解Spring Cloudhttps://thinkwon.blog.csdn.net/article/details/103715146
    2Spring Cloud入门-Eureka服务注册与发现(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103726655
    3Spring Cloud入门-Ribbon服务消费者(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103729080
    4Spring Cloud入门-Hystrix断路器(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103732497
    5Spring Cloud入门-Hystrix Dashboard与Turbine断路器监控(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103734664
    6Spring Cloud入门-OpenFeign服务消费者(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103735751
    7Spring Cloud入门-Zuul服务网关(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103738851
    8Spring Cloud入门-Config分布式配置中心(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103739628
    9Spring Cloud入门-Bus消息总线(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103753372
    10Spring Cloud入门-Sleuth服务链路跟踪(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103753896
    11Spring Cloud入门-Consul服务注册发现与配置中心(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103756139
    12Spring Cloud入门-Gateway服务网关(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103757927
    13Spring Cloud入门-Admin服务监控中心(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103758697
    14Spring Cloud入门-Oauth2授权的使用(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103761687
    15Spring Cloud入门-Oauth2授权之JWT集成(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103763364
    16Spring Cloud入门-Oauth2授权之基于JWT完成单点登录(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103766368
    17Spring Cloud入门-Nacos实现注册和配置中心(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103769680
    18Spring Cloud入门-Sentinel实现服务限流、熔断与降级(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103770879
    19Spring Cloud入门-Seata处理分布式事务问题(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103786102
    20Spring Cloud入门-汇总篇(Hoxton版本)https://thinkwon.blog.csdn.net/article/details/103786588

    服务注册发现

    服务配置

    负载均衡

    服务调用

    服务限流

    熔断降级

    网关路由

    服务权限

    链路追踪

    分布式事务

    分布式缓存

    分布式会话

    日志收集

    服务监控

    消息驱动

    数据处理流

    自动化测试与部署

    第三方支持

    分布式协调服务Zookeeper

    程序员的一些思考

    序号内容链接地址
    1程序员写个人技术博客的价值与意义https://thinkwon.blog.csdn.net/article/details/102980571
    2Java知识体系最强总结(2020版)https://thinkwon.blog.csdn.net/article/details/103592572
    3博客之星,有你的鼓励更精彩https://thinkwon.blog.csdn.net/article/details/112517796

    团队与项目管理

    需求调研

    项目管理

    序号内容链接地址
    1Worktile、Teambition与Tower项目管理软件对比https://thinkwon.blog.csdn.net/article/details/106064807

    代码管理

    文档管理

    序号内容链接地址
    1几款常见接口管理平台对比https://thinkwon.blog.csdn.net/article/details/106064883
    2Swagger2常用注解说明https://thinkwon.blog.csdn.net/article/details/107477801

    测试

    Python

    序号内容链接地址
    1Win10安装Python3.9https://thinkwon.blog.csdn.net/article/details/112411897
    2Anaconda安装https://thinkwon.blog.csdn.net/article/details/112412165
    3PyCharm2020.3.2安装https://thinkwon.blog.csdn.net/article/details/112412497
    4PyCharm常用配置和常用插件https://thinkwon.blog.csdn.net/article/details/112412783

    运维

    常规监控

    APM

    持续集成(CI/CD):Jenkins,环境分离

    自动化运维:Ansible,puppet,chef

    测试:TDD 理论,单元测试,压力测试,全链路压测,A/B 、灰度、蓝绿测试

    虚拟化:KVM,Xen,OpenVZ

    容器技术:Docker

    云技术:OpenStack

    DevOps

    操作系统

    计算机操作系统

    计算机原理

    Linux

    CPU

    进程,线程,协程

    CentOS8

    序号内容链接地址
    1VMware Workstation Pro 16搭建CentOS8虚拟机集群https://thinkwon.blog.csdn.net/article/details/115058171
    2CentOS8安装Dockerhttps://thinkwon.blog.csdn.net/article/details/115056214
    3CentOS8搭建Nacos1.4.0集群https://thinkwon.blog.csdn.net/article/details/115056401
    4CentOS8安装GitLab13.7.2https://thinkwon.blog.csdn.net/article/details/115056528
    5CentOS8安装MySQL8https://thinkwon.blog.csdn.net/article/details/115055934

    推荐书籍

    序号内容链接地址
    1读书清单-计算机https://thinkwon.blog.csdn.net/article/details/108077754

    读书笔记

    序号内容链接地址
    1高效休息法-读书笔记https://thinkwon.blog.csdn.net/article/details/118638191
    2斯坦福高效睡眠法-读书笔记https://thinkwon.blog.csdn.net/article/details/108349844
    3高效能人士的七个习惯-读书笔记https://thinkwon.blog.csdn.net/article/details/108941111
    4富爸爸穷爸爸-读书笔记https://thinkwon.blog.csdn.net/article/details/109261723
    5如何阅读一本书-读书笔记https://thinkwon.blog.csdn.net/article/details/115422659
    6人性的弱点-读书笔记https://thinkwon.blog.csdn.net/article/details/116809824
    7麦肯锡极简工作法-读书笔记https://thinkwon.blog.csdn.net/article/details/118638191

    云计算

    IaaS、SaaS、PaaS、虚拟化技术、openstack、Serverlsess

    搜索引擎

    Solr、Lucene、Nutch、Elasticsearch

    权限管理

    Shiro、Spring Security

    区块链

    哈希算法、Merkle树、公钥密码算法、共识算法、Raft协议、Paxos 算法与 Raft 算法、拜占庭问题与算法、消息认证码与数字签名

    展开全文
  • oracle DES加密解密与Java DES加密解密

    千次阅读 2021-06-14 14:55:04
    oracleDES加密函数 create or replace function encrypt_des(p_text varchar2, p_key varchar2) return varchar2 is v_text varchar2(4000); v_enc varchar2(4000); raw_input RAW(128) ; key_input RAW(128) ...

    有时间加密信息里会包含特殊字符,DES在处理特殊字符的时候会报错

    我的处理是先把内容转化成base64再去加密DES 

    内容转换成 base64

    CREATE OR REPLACE function
    encrypt_base64(p_text varchar2) return varchar2 is
        v_enc varchar2(8000);
        begin
        v_enc := utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(p_text)));
        return v_enc;
    end;

    base64 转换回内容 

    CREATE OR REPLACE function 
    decrypt_base64(p_text varchar2) return varchar2 is
        v_enc varchar2(4000);
        begin
        v_enc := utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(p_text)));
        return v_enc;
    end;

    oracle DES加密函数

    CREATE OR REPLACE function encrypt_des(p_text varchar2, p_key varchar2)
    return varchar2 
    is
        v_text varchar2(8000);
        v_enc  varchar2(8000);
        v_source varchar2(8000);
        raw_input RAW(256) ;
        key_input RAW(256) ;
        decrypted_raw RAW(4048);
    begin
        v_text := rpad( encrypt_base64(p_text), (trunc(length(encrypt_base64(p_text))/8)+1)*8, chr(0));
        raw_input := UTL_RAW.CAST_TO_RAW(v_text);
        key_input := UTL_RAW.CAST_TO_RAW(p_key);    
        dbms_obfuscation_toolkit.DESEncrypt(input => raw_input,key => key_input,encrypted_data =>decrypted_raw);
        v_enc := rawtohex(decrypted_raw);
        dbms_output.put_line(v_enc);
        return v_enc;
    end;

    oracle DES解密函数

    CREATE OR REPLACE function decrypt_des(p_text varchar2,p_key varchar2) return varchar2 is
        v_text varchar2(2000);
    begin
       IF p_text is null or p_text='' THEN  
           return  '';
       ELSE
          begin 
             dbms_obfuscation_toolkit.DESDECRYPT(input_string => UTL_RAW.CAST_TO_varchar2(p_text),key_string =>p_key,decrypted_string=> v_text);
             v_text := rtrim(v_text,chr(0));
             dbms_output.put_line(v_text);
             return decrypt_base64(v_text);
          end;
       END IF;
    end;

    oracle 测试

      

    Java DES加密解密

    package org.interestinglab.waterdrop.utils;
    
    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESKeySpec;
    import javax.crypto.spec.IvParameterSpec;
    import javax.xml.bind.DatatypeConverter;
    
    import org.apache.commons.codec.binary.Hex;
    import java.io.IOException;
    
    /**
     * @Description: 对应 oracle DES加密解密方法
     * @Author: 程序工厂
     * @Date:   2021-08-24
     * @Version: V1.0
     */
    public class DESUtil {
    
        //密匙
        private static String key = "567G5ABVC";
    
        public static void main(String[] args) throws IOException {
            String oriValue = "测试测试测试测试测试测试测试测试";
            System.out.println("加密参数 ----> " + oriValue);
            oriValue = BASE64Util.encoder(oriValue);
            System.out.println("参数 BASE64 编码 ----> " + oriValue);
            if(oriValue != null){
                oriValue = ENCRYPT_DES(oriValue);
            }
            System.out.println("DES 加密 ----> " + oriValue);
            oriValue = DECRYPT_DES(oriValue);
            System.out.println("DES 解密 ----> " + oriValue);
            oriValue = BASE64Util.decoder(oriValue);
            System.out.println("参数 BASE64 解码 ----> " + oriValue);
        }
    
        /**
         * 对应数据库DECRYPT_DES函数
         * @param inStr 解密参数
         * @return
         */
        public static String DECRYPT_DES(String inStr) {
            try {
                DESKeySpec desKey = new DESKeySpec(key.getBytes());
                SecretKey securekey = SecretKeyFactory.getInstance("DES").generateSecret(desKey);
                Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
                cipher.init(Cipher.DECRYPT_MODE, securekey, new IvParameterSpec(new byte[8]));
                byte[] decryptBytes = cipher.doFinal(Hex.decodeHex(inStr.toCharArray()));
                return new String(decryptBytes).trim();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 对应数据库ENCRYPT_DES函数
         * @param encryptStr 加密参数
         * @return
         */
        public static String ENCRYPT_DES(String encryptStr) {
            try {
                DESKeySpec desKey = new DESKeySpec(key.getBytes());
                SecretKey securekey = SecretKeyFactory.getInstance("DES").generateSecret(desKey);
                Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
                cipher.init(Cipher.ENCRYPT_MODE, securekey, new IvParameterSpec(new byte[8]));
                byte[] inBytes = new byte[((int) (encryptStr.length() / 8) + 1) * 8];
                for (int i = 0; i < encryptStr.length(); i++) {
                    inBytes[i] = encryptStr.getBytes()[i];
                }
                byte[] enBytes = cipher.doFinal(inBytes);
                return DatatypeConverter.printHexBinary(enBytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    Java BASE64 编码、解密

    package org.interestinglab.waterdrop.utils;
    
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    import java.io.IOException;
    
    /**
     * @Description: 对应 oracle BASE64 编码、解密
     * @Author: 程序工厂
     * @Date:   2021-08-24
     * @Version: V1.0
     */
    public class BASE64Util {
    
        /**
         * 编码
         * @param text
         * @return
         * @throws IOException
         */
        public static String encoder(String text) throws IOException {
            final BASE64Encoder encoder = new BASE64Encoder();
            final byte[] textByte = text.getBytes("GBK");
            return encoder.encode(textByte);
        }
    
        /**
         * 解码
         * @param text
         * @return
         * @throws IOException
         */
        public static String decoder(String text) throws IOException {
            final BASE64Decoder decoder = new BASE64Decoder();
            return new String(decoder.decodeBuffer(text), "GBK");
        }
    
    }
    

    Java 测试 

    展开全文
  • 前段时间由于项目需要,使用java生成PDF文件,然后将文件压缩成ZIP格式,同时对压缩文件进行加密,先将代码及jar包上传供大家参考,并希望大家共同完善和学习。 java生成PDF,java加密压缩文件并,java生成PDF后压缩...
  • java 加密解密时间戳

    千次阅读 2017-08-26 15:22:05
    今天献上一个将时间戳加密成一个21位大写英文字母串的java代码,并附上解密代码,思路很简单,仅供娱乐private Map, String> codeMap; private String englishChars; private ArrayList<Integer> changeIndex; ...

    今天献上一个将时间戳加密成一个21位大写英文字母串的java代码,并附上解密代码,思路很简单,仅供娱乐

    private Map<Character, String> codeMap; 
    private String englishChars;
    private ArrayList<Integer> changeIndex;
    public SimpleDateFormat sdf;
    
    /**
         * 加密时间
         * @author huzhen
         * @since 2017/7/12
         * @param date date()类型时间
         * */
        public String enTimeCode(Date enDate){
            String dataStr = null;
            try{
                dataStr = this.getSdf().format(enDate);
                String enStr = "";
                for(int i=0; i<dataStr.length(); i++){
                    String transLetter = this.getCodeMap().get(dataStr.charAt(i));
                    enStr = enStr + transLetter;
                }
                int changeCusor = 0;
                StringBuffer retStr = new StringBuffer(generateRandString(21));
                for(int i=0; i<retStr.length(); i++){
                    if(this.getChangeIndex().contains(i)){
                        retStr.setCharAt(i, enStr.charAt(changeCusor));
                        changeCusor++;
                    }
                }
                return retStr.toString();
            }catch(Exception e){
                //e.printStackTrace(); 
                System.out.println(e.getMessage());
                return "";
            }
        }
    
    /**
         * 将加密后的乱码解密
         * @author huzhen
         * @since 2017/7/12
         * @param date date()类型时间
         * */
        public Date deTimeCode(String enStr){
            String dateStr = "";
            try{
                String toDecodeStr = "";
                for(int i=0; i<enStr.length(); i++){
                    if(this.getChangeIndex().contains(i)){
                        toDecodeStr = toDecodeStr + enStr.charAt(i);
                    }               
                }
                for(int i=0; i<toDecodeStr.length(); i++){
                    char deChar = valueGetKey(this.getCodeMap(), String.valueOf(toDecodeStr.charAt(i))).get(0);
                    if(deChar != '\0'){
                        dateStr += deChar;
                    }               
                }
            return this.getSdf().parse(dateStr);
            }catch(Exception e){
                //e.printStackTrace(); 
                System.out.println(enStr + "不符合规则!");
                return null;
            }
        }
    
    
    private Map<Character, String> getCodeMap() {
            if(codeMap == null){
                codeMap = new HashMap<Character, String>();
                codeMap.put('0', "I");
                codeMap.put('1', "L");
                codeMap.put('2', "O");
                codeMap.put('3', "V");
                codeMap.put('4', "E");
                codeMap.put('5', "M");
                codeMap.put('6', "Y");
                codeMap.put('7', "D");
                codeMap.put('8', "N");
                codeMap.put('9', "S");
            }
            return codeMap;
        }
    
        private static ArrayList<Character> valueGetKey(Map<Character, String> map, String value) {
            Set<Entry<Character, String>> set = map.entrySet();
            ArrayList<Character> arr = new ArrayList<Character>();
            Iterator<Entry<Character, String>> it = set.iterator();
            while(it.hasNext()) {
                 Map.Entry<Character, String> entry = (Map.Entry<Character, String>)it.next();
                 if(entry.getValue().equals(value)) {
                       char s = (char)entry.getKey();
                       arr.add(s);
                 }
            }
            return arr;
        }
    
    
        private String getEnglishChars() {
            if(englishChars == null){
                englishChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            }
            return englishChars;
        }
    
        private SimpleDateFormat getSdf() {
            if(sdf == null){
                sdf = new SimpleDateFormat("yyyyMMdd");
            }
            return sdf;
        }
    
        public ArrayList<Integer> getChangeIndex() {
            if(changeIndex == null){
                changeIndex = new ArrayList<Integer>();
                changeIndex.add(1);
                changeIndex.add(6);
                changeIndex.add(9);
                changeIndex.add(13);
                changeIndex.add(14);
                changeIndex.add(17);
                changeIndex.add(19);
                changeIndex.add(20);
            }
            return changeIndex;
        }
    
    /**
         * 随机生成指定位数的大写英文字母串
         * @author huzhen
         * @since 2017/7/12
         * @param 
         * */
        private String generateRandString(int bits){
            String retStr = "";
            for(int i=0; i<bits; i++){
                retStr = retStr + this.getEnglishChars().charAt((int)(Math.random() * 26));
            }
            return retStr;
        }
    展开全文
  • 有一段时间,我一直在使用 PGP 实用程序,该实用程序还提供基于密码的加密并创建自解密档案。 我真的很喜欢自解密功能,但因为它是基于 Windows 的,所以我不能在任何其他平台上使用它。 可能最具移动性的解决方案...
  • java加密与解密(二)

    千次阅读 2019-06-30 13:38:58
    七、 高等数据加密——非对称加密算法 我们可能没有在瑞士苏黎世银行存入巨额资产的机会,但相信大多数人都在电影中见到这样一组镜头:户主带着自己的钥匙来到银行,要求取出自己寄放的物品。银行工作人员验明户主...

    七、 高等数据加密——非对称加密算法
            我们可能没有在瑞士苏黎世银行存入巨额资产的机会,但相信大多数人都在电影中见到这样一组镜头:户主带着自己的钥匙来到银行,要求取出自己寄放的物品。银行工作人员验明户主身份后,拿出另一把钥匙同户主一起打开保险柜,将用户寄放的物品取出。我们可以把这个保险柜称为“双钥保险柜”。
           与第6部分提到的密码日记本不同,要开启双钥保险柜同时需要两把钥匙:一把钥匙留给户主,由户主保管,我们可以把它叫做“公钥”;另一把钥匙留给银行,由银行保管,我们可以把它叫做“私钥”。
           如果将上述内容引申为加密/解密应用,我们就能体会到非对称加密算法与对称加密算法之间的区别。对称加密算法仅有一个密钥,既可用于加密,亦可用于解密。若完成加密/解密操作,仅需要一个密钥即可;而非对称加密算法拥有两个密钥,一个用于加密,另一个则用于解密。若要完成加密/解密操作,需要两个密钥同时参与。
           相比与对称加密算法的单钥体系,非对称加密算法的双钥体系就更为安全。但非对称加密的缺点是加解密速度要远远慢于对称加密,在某些极端情况下,非对称加密算法甚至比非对称加密要慢1000倍。

    7.1 非对称加密算法概述

          非对称加密算法与对称加密算法的主要差异在于非对称加密用于加密和解密的密钥不相同,一个公开,称为公钥;一个保密,称为私钥。因此,非对称加密也称为双钥或公钥加密算法。

          非对称加密算法解决了 对称加密算啊密钥分配问题,病极大地提高了算法安全性。多种B2C或B2B应用均使用非对称加密算法作为数据加密的核心算法。

    7.1.1 非对称加密算法的由来
           密钥管理是对称加密算法系统不容忽视的问题,它成为安全系统中最为薄弱的环节。为了弥补这一弱势,非对称加密算法应运而生。
           1976年,W.Diffie和M.Hellman在IEEE(Institute of Electrical and Electronics Engineers,美国电气和电子工程师协会)的刊物上发表《密码学的新方向》一文,首次提出非对称加密算法。
           非对称加密算法有别于对称加密算法,将密钥一分为二,公钥公开,私钥保密。公钥通过非安全通道发放,私钥则由发放者保留。公钥与私钥相对应,成对出现。公钥加密的数据,只可使用私钥对其解密。反之,私钥加密的数据,只可使用公钥对其解密。
           非对称加密算法与对称加密算法相比,密钥管理问题不复存在,在安全性上有着无法逾越的高度,但却无法回避加密/解密效率低这一问题。因此,非对称加密算法往往应用在一些安全性要求相当高的领域,如B2C、B2B等电子商务平台。注意 针对非对称加密算法的低效问题,各密码学机构主张将对称加密算法与非对称加密算法相结合,使用对称加密算法为数据加密/解密,使用公钥和私钥为对称加密算法密钥加密/解密。利用对称加密算法的高效性,加之非对称加密算法的密钥管理,提升整体加密系统的安全性。在算法设计上,非对称加密算法对待加密数据长度有着极为苛刻的要求。例如,RSA算法要求待加密数据不得大于53个字节。非对称加密算法主要用于交换对称加密算法的秘密密钥,而非数据交换。

    7.1.2 非对称加密算法的家谱
           非对称加密算法源于DH算法(Diffie-Hellman,密钥交换算法),由W.Diffie和M.Hellman共同提出。该算法为非对称加密算法奠定了基础,堪称非对称加密算法之鼻祖。
    DH算法提出后,国际上相继出现了各种实用性更强的非对称加密算法,其构成主要是基于数学问题的求解,主要分为两类:
           基于因子分解难题。RSA算法是最为典型的非对称加密算法,该算法由美国麻省理工学院(MIT)的Ron Rivest、AdiShamir和Leonard Adleman三位学者提出,并以这三位学者的姓氏开头字母命名,称为RSA算法。RSA算法是当今应用范围最为广泛的非对称加密算法,也是第一个既能用于数据加密也能用于数字签名的算法。
           基于离散对数难题。ElGamal算法由Taher ElGamal提出,以自己的名字命名。该算法既可用于加密/解密,也可用于数字签名,并为数字签名算法形成标准提供参考。美国的DSS(Digital Signature Standard,数据签名标准)的DSA(Digital Signature Algorithm,数字签名算法)经ElGamal算法演变而来。
           ECC(Elliptical Curve Cryptography,椭圆曲线加密)算法以椭圆曲线理论为基础,在创建密钥时可做到更快、更小,并且更有效。ECC 算法通过椭圆曲线方程式的性质产生密钥,而不是采用传统的方法利用大质数的积来产生。
           在Java 6中仅提供了DH和RSA两种算法实现,而在Java 7中新增了ECDH算法实现,用于增强密钥交换算法,提升HTTPS服务的安全性。通过Boucy Castle可以获得ElGamal算法支持。

    7.2 密钥交换算法——DH&ECDH
           对称加密算法提高数据安全性的同时带来了密钥管理的复杂性。消息收发双方若想发送加密消息,必须事先约定好加密算法并发放密钥。而如何安全的传递密钥,成为对称加密算法的一个棘手问题。密钥交换算法(Diffie-Hellman算法,简称DH算法)成为解决这一问题的金钥匙!

    7.2.1 简述
           1976年,W.Diffie和M.Hellman在发表的论文中提出了公钥加密算法思想,但当时并没有给出具体的实施方案,原因在于没有找到单向函数(也就是消息摘要算法),但在该文中给出了通信双方通过信息交换协商密钥的算法,即Diffie-Hellman密钥交换算法(通常简称为DH算法)。该算法的目的在于让消息的收发双方可以在安全的条件下交换密钥,以备后续加密/解密使用。因此,DH算法是第一个密钥协商算法,但仅能用于密钥分配,不能用于加密或解密消息。
           DH密钥交换算法的安全性基于有限域上的离散对数难题。基于这种安全性,通过DH算法进行密钥分配,使得消息的收发双方可以安全地交换一个秘密密钥,再通过这个密钥对数据进行加密和解密处理。
    ECDH是基于椭圆曲线加密算法的密钥交换算法(这里将ECC简化为EC,同知椭圆曲线加密算法),密钥较短但密钥安全性更强,其原理与DH算法完全一致。

    7.2.2 DH实现
           Java 7提供了DH算法的相关实现,相关Java API的知识可阅读第3章内容。作为对称加密算法向非对称加密算法的一种过渡,DH算法的实现是我们了解非对称加密算法的最佳途径。
          有关DH算法的Java 7实现细节如表所示。

                                                                 上图为DH算法

          所有非对称算法实现的公有方法均不使用java.security和javax.crypto包及其子包中的接口或类作为参数或返回值。
    实现DH算法密钥需要用到密钥对及密钥对生成器,如代码清单7-1所示。
    代码清单7-1 构建DH算法甲方密钥对  

    // 实例化密钥对生成器
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
    // 初始化密钥对生成器
    keyPairGenerator.initialize(1024);
    // 生成密钥对
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    // 公钥
    PublicKey publicKey = keyPair.getPublic();
    // 私钥
    PrivateKey privateKey = keyPair.getPrivate();

     如果有必要,我们需要使用DH算法专用公钥/私钥接口(DHPublicKey/DHPrivateKey)强行转换上述密钥。
    上述代码完成了甲方密钥的构建,要构建乙方密钥需要使用甲方公钥,具体实现如代码清单7-2所示。
    代码清单7-2 构建DH算法乙方密钥对
    // 由甲方公钥构建乙方密钥
    DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();
    // 实例化密钥对生成器
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
    // 初始化密钥对生成器
    keyPairGenerator.initialize(dhParamSpec);
    // 生成密钥对
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    // 公钥
    PublicKey publicKey = keyPair.getPublic();
    // 私钥
    PrivateKey privateKey = keyPair.getPrivate();  

    密钥仅能以二进制编码形式出现。因此,我们通过Map对象

    封装密钥,如代码清单7-3所示。
    代码清单7-3 封装DH算法密钥
    // 将密钥对存储在Map中
    Map<String, Object> keyMap = new HashMap<String, Object>(2);
    keyMap.put("DHPublicKey", publicKey);
    keyMap.put("DHPrivateKey", privateKey);

    我们将在后续的initKey()方法中见到上述代码。
    如果要将密钥材料转换为密钥对象,可参考代码清单7-4。
    代码清单7-4 转换密钥材料
    // 实例化密钥工厂
    KeyFactory keyFactory = KeyFactory.getInstance("DH");
    // 初始化公钥
    // 公钥密钥材料转换
    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
    // 产生公钥
    PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
    // 初始化私钥
    // 私钥密钥材料转换
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
    // 产生私钥

    PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

    完成甲乙方密钥的构建操作后,我们便可以完成本地密钥的构建。这里,要求使用不对称的公钥和私钥来构建本地密钥,即使用甲方私钥和乙方公钥构建甲方本地密钥;使用乙方私钥和甲方公钥构建乙方本地密钥。相关实现如代码清单7-5所示。
    代码清单7-5 构建本地密钥
    // 实例化
    KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
    // 初始化
    keyAgree.init(priKey);
    keyAgree.doPhase(pubKey, true);
    // 生成本地密钥
    SecretKey secretKey = keyAgree.generateSecret("AES");

    完成了上述准备后,我们接下来仅仅需要使用本地密钥进行加密/解密操作了。本地密钥就是对称加密算法中的秘密密钥,对于对称加密算法的加密/解密操作,我们在第7章中已经详尽描述,就不在此复述了。完整的代码实现如代码清单7-6所示。
    代码清单7-6 DH算法实现

    import java.security.Key;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PublicKey;
    import java.security.PrivateKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.HashMap;
    import java.util.Map;
    import javax.crypto.Cipher;
    import javax.crypto.KeyAgreement;
    import javax.crypto.SecretKey;
    import javax.crypto.interfaces.DHPrivateKey;
    import javax.crypto.interfaces.DHPublicKey;
    import javax.crypto.spec.DHParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    /**
     * DH安全编码组件
     * @version 1.0
     */
    public abstract class DHCoder {
      // 非对称加密密钥算法
      public static final String KEY_ALGORITHM = "DH";
      /**
      * 本地密钥算法,即对称加密密钥算法,
    * 可选DES、DESede和AES算法
      */
      public static final String SECRET_ALGORITHM = "AES";
      /**
      * 密钥长度
      * DH算法默认密钥长度为1024
      * 密钥长度必须是64的倍数,其范围在512位到1024位之间。
      */
      private static final int KEY_SIZE = 512;
      // 公钥
      private static final String PUBLIC_KEY = "DHPublicKey";
      // 私钥
      private static final String PRIVATE_KEY = "DHPrivateKey";
      /**
      * 初始化甲方密钥
      * @return Map 甲方密钥Map
      * @throws Exception
      */
      public static Map<String, Object> initKey() throws Exception {
         // 实例化密钥对生成器
         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
         // 初始化密钥对生成器
    keyPairGenerator.initialize(KEY_SIZE);
         // 生成密钥对
         KeyPair keyPair = keyPairGenerator.generateKeyPair();
         // 甲方公钥
         DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
         // 甲方私钥
         DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
         // 将密钥对存储在Map中
         Map<String, Object> keyMap = new HashMap<String, Object>(2);
         keyMap.put(PUBLIC_KEY, publicKey);
         keyMap.put(PRIVATE_KEY, privateKey);
         return keyMap;
      }
      /**
      * 初始化乙方密钥
      * @param key 甲方公钥
      * @return Map 乙方密钥Map
      * @throws Exception
      */
      public static Map<String, Object> initKey(byte[] key) throws Exception {
         // 解析甲方公钥
         // 转换公钥材料
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
    / 实例化密钥工厂
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 产生公钥
         PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
         // 由甲方公钥构建乙方密钥
         DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();
         // 实例化密钥对生成器
         KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
         // 初始化密钥对生成器
         keyPairGenerator.initialize(dhParamSpec);
         // 产生密钥对
         KeyPair keyPair = keyPairGenerator.genKeyPair();
         // 乙方公钥
         DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
         // 乙方私钥
         DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
         // 将密钥对存储在Map中
         Map<String, Object> keyMap = new HashMap<String, Object(2);
         keyMap.put(PUBLIC_KEY, publicKey);
         keyMap.put(PRIVATE_KEY, privateKey);
         return keyMap;
      }
    /**
      * 加密
      * @param data 待加密数据
      * @param key 密钥
      * @return byte[] 加密数据
      * @throws Exception
      */
    public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
         // 生成本地密钥
         SecretKey secretKey = new SecretKeySpec(key, SECRET_ ALGORITHM);
         // 数据加密
         Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, secretKey);
         return cipher.doFinal(data);
      }
    /**
    *构建密钥
    *@param publicKey 公钥
    *@param privateKey私钥
    *@return byte[]本地密钥
    *@throw Exception
    */
    public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) throws Exception {
         // 实例化密钥工厂
         KeyFactory keyFactory =KeyFactory.getInstance(KEY_ALGORITHM);
         // 初始化公钥
         // 密钥材料转换
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
         // 产生公钥
         PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
         // 初始化私钥
         // 密钥材料转换
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
    // 产生私钥
         PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
         // 实例化
         KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
         // 初始化
         keyAgree.init(priKey);
         keyAgree.doPhase(pubKey, true);
         // 生成本地密钥
         SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
    teturn secretKey.getEncoded();
    }
    /**
    *@param keyMap 密钥Map
    *@return byte[]私钥
    *@throw Exception
    */
    public static byte[] getPrivateKey(Map<String,Object>keyMap)throws Exception{
    Key key=(Key)keyMap.get(PRIVATE_KEY);
    return key.getEncoded();
    }
    /**
      * 取得公钥
      * @param keyMap 密钥Map
      * @return byte[] 公钥
      * @throws Exception
      */
      public static byte[] getPublicKey(Map<String, Object> keyMap)
             throws Exception {
         Key key = (Key) keyMap.get(PUBLIC_KEY);
         return key.getEncoded();
      }
    }
    
    

             对于DH算法的测试,我们需要关注两点:一点是甲乙方的本地密钥是否相同;另一点是甲方加密后的数据,乙方是否能够解析,反之亦然。
    完整的DH算法测试用例如代码清单7-7所示。
    代码清单7-7 DH算法实现测试用例                                        

    import static org.junit.Assert.*;
    import java.util.Map;
    import org.apache.commons.codec.binary.Base64;
    import org.junit.Before;
    import org.junit.Test;
    /**
     * DH校验
     * @version 1.0
     */
    public class DHCoderTest {
      // 甲方公钥
      private byte[] publicKey1;
      // 甲方私钥
      private byte[] privateKey1;
      // 甲方本地密钥
      private byte[] key1;
      // 乙方公钥
      private byte[] publicKey2;
      // 乙方私钥
      private byte[] privateKey2;
      // 乙方本地密钥
      private byte[] key2;
    /**
      * 初始化密钥
      * @throws Exception
      */
      @Before
      public final void initKey() throws Exception {
         // 生成甲方密钥对
         Map<String, Object> keyMap1 = DHCoder.initKey();
         publicKey1 = DHCoder.getPublicKey(keyMap1);
         privateKey1 = DHCoder.getPrivateKey(keyMap1);
         System.err.println("甲方公钥:\n" + Base64.encodeBase64String (publicKey1));
         System.err.println("甲方私钥:\n" + Base64.encodeBase64String (privateKey1));
         // 由甲方公钥产生本地密钥对
         Map<String, Object> keyMap2 = DHCoder.initKey(publicKey1);
         publicKey2 = DHCoder.getPublicKey(keyMap2);
         privateKey2 = DHCoder.getPrivateKey(keyMap2);
         System.err.println("乙方公钥:\n" + Base64.encodeBase64String (publicKey2));
         System.err.println("乙方私钥:\n" + Base64.encodeBase64String (privateKey2));
         key1 = DHCoder.getSecretKey(publicKey2, privateKey1);
    System.err.println("甲方本地密钥:\n" + Base64.encodeBase64String(key1));
         key2 = DHCoder.getSecretKey(publicKey1, privateKey2);
         System.err.println("乙方本地密钥:\n" + Base64.encodeBase64String(key2));
         // 校验
         assertArrayEquals(key1, key2);
      }
      /**
      * 校验
      * @throws Exception
      */
      @Test
      public final void test() throws Exception {
         System.err.println("\n=====甲方向乙方发送加密数据=====");
         String input1 = "密码交换算法";
         System.err.println("原文: " + input1);
         System.err.println("---使用甲方本地密钥对数据加密---");
         // 使用甲方本地密钥对数据加密
         byte[] code1 = DHCoder.encrypt(input1.getBytes(), key1);
         System.err.println("加密: " + Base64.encodeBase64String(code1));
         System.err.println("---使用乙方本地密钥对数据解密---");
         // 使用乙方本地密钥对数据解密
         byte[] decode1 = DHCoder.decrypt(code1, key2);
         String output1 = (new String(decode1));
    System.err.println("解密: " + output1);
         assertEquals(input1, output1);
         System.err.println("\n=====乙方向甲方发送加密数据=====");
         String input2 = "DH";
         System.err.println("原文: " + input2);
         System.err.println("---使用乙方本地密钥对数据加密---");
         // 使用乙方本地密钥对数据加密
         byte[] code2 = DHCoder.encrypt(input2.getBytes(), key2);
         System.err.println("加密: " + Base64.encodeBase64String(code2));
         System.err.println("---使用甲方本地密钥对数据解密---");
         // 使用甲方本地密钥对数据解密
         byte[] decode2 = DHCoder.decrypt(code2, key1);
         String output2 = (new String(decode2));
         System.err.println("解密: " + output2);
         // 校验
         assertEquals(input2, output2);
      }
    }

    按照惯例,我们使用Base64算法对密钥编码,在控制台得到相关信息,如以下代码:
    甲方公钥:
    MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
    kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBAJei+kbWCpbA
    EiXXcMrj991qHahR6nSQ4EfKqBah4+apd+zV92iy1C+rwsv8ea2V43zhesySZcylPnosfBl7haA=
    甲方私钥:
    MIHRAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
    rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
    TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQyAjA1b4WOjC0x
    efoTnRX9Y7cZ5EhVh2lqaOZxdaHMA1U4LMKQZQmNIewW796UkVWeW9o=
    乙方公钥:
    MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
    W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
    kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAEdxKB72W1Sgq
    /QRhh7WOXS31arbo55hEdLDn9vL5PT26rlaEQ5i2wECCJ0zXHIXInQHaxbftwP734Ar/vvMMBQ==

    乙方私钥:
    MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
    rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
    TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAog1vG/Nm
    PHuVfVUHe53MkO1jTNDXYFPpY92+G6BCEzeweNDEoRj8EVQdClf7xz+t

    不论公钥还是私钥,不论甲方还是乙方对密钥的长度都难以接受。若作者选择1024位的密钥长度,控制台输出的密钥信息打印出来恐怕要够两页A4纸了。
    甲乙方的本地密钥是否相同呢?我们将其通过Base64编码,在控制台中得到如下信息:
    甲方本地密钥:
    FNDVElg+KyfttpT81YWHsiaTYNs2e0fzhf8OwCDWUGs=
    乙方本地密钥:
    FNDVElg+KyfttpT81YWHsiaTYNs2e0fzhf8OwCDWUGs=

    显然,甲乙方的本地密钥是一致的。
    接下来验证甲方加密的数据乙方是否可以解密,在控制台中得到如下信息:
    =====甲方向乙方发送加密数据=====
    原文: 密码交换算法
    ---使用甲方本地密钥对数据加密---

    加密: IyzI6a6HyEq4927UoHQ8jIgMrA9RFtKf2Hcd/503eTM=
    ---使用乙方本地密钥对数据解密---
    解密: 密码交换算法

    反之,验证乙方加密的数据甲方是否可以解密,在控制台中得到如下信息:
    =====乙方向甲方发送加密数据=====
    原文: DH
    ---使用乙方本地密钥对数据加密---
    加密: OVvejG+sj98I7BIqLGWpmA==
    ---使用甲方本地密钥对数据解密---
    解密: DH

    通过上述测试,我们可以验证:经由甲乙双方构建的秘密密钥相同,基于DH算法实现的加密通信系统实际上是使用同一个秘密密钥完成相应的加密/解密对称加密系统。
    对于DH算法而言,算法的安全强度在于密钥长度和对称加密算法的选择。
    ❑DH算法支持的密钥长度为64的倍数位,取值范围在512~1024位(含1024位)之间。密钥长度与加密安全强度成正比,与运算时间成反比。在使用时,需选择合适的密钥长度。
    ❑对称加密算法可以选择DES、DESede和AES算法等。
    合理选择密钥长度和对称加密算法是构建基于DH算法密码系统的关键。

    7.2.3 ECDH实现
          从Java 7开始,增加了椭圆曲线密钥交换算法ECDH,其原理与DH算法相同,在实现细节上略有不同。有关ECDH算法的Java 7实现细节如下表所示。

    在代码实现方面,ECDH算法与DH算法的差别主要是密钥长度和对称加密算法。
    ECDH算法密钥长度似乎没有什么规律,官方也没有明确说明。从作者对密钥长度的测试结果来看,ECDH算法密钥长度共有3种:112、256和571位。
    在Java 6中,ECDH算法密钥生成是个很困难的工作,需要一段冗长的代码,且生成一对固定密钥,非常不方便。而在Java 7中,密钥生成和其他非对称加密算法完全一致,如代码清单7-8所示。
    代码清单7-8 ECDH密钥生成 

    // 实例化密钥对生成器

    KeyPairGenerator keyPairGenerator =KeyPairGenerator.getInstance(“ECDH”);

    // 初始化密钥对生成器
    keyPairGenerator.initialize(571);

    // 生成密钥对
    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    // 甲方公钥
    ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();

    // 甲方私钥
    ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();

    这里主要注意初始化密钥长度——112、256或571位。

    ECDH算法的密钥实际上也是EC算法的密钥,初始化密钥对生成器时,使用“EC”代替“ECDH”也可以。ECDH算法对交换的密钥算法支持还不能像DH算法那样全面,作者尝试使用AES、DES和DESede算法构建本地密钥均告失败,但Blowfish、RC2和RC4都可以正常使用。详见代码清单7-9所示。
    代码清单7-9 密钥对初始化和本地密钥初始化
    // 初始化密钥对,EC或ECDH
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");

    // …
    // 生成本地密钥,Blowfish、RC2或RC4
    SecretKey secretKey = keyAgree.generateSecret("Blowfish");

    完整的DH算法测试用例如代码清单7-10所示。
    代码清单7-10 ECDH算法实现

    import java.security.Key;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.interfaces.ECPrivateKey;
    import java.security.interfaces.ECPublicKey;
    import java.security.spec.ECParameterSpec;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.HashMap;
    import java.util.Map;
    import javax.crypto.Cipher;
    import javax.crypto.KeyAgreement;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    /**
     * ECDH安全编码组件
     * @version 1.0
     */
    public abstract class ECDHCoder {
        /**
        * 非对称加密密钥算法,EC或ECDH
        */
        public static final String KEY_ALGORITHM = "ECDH";
        /**
        * 本地密钥算法,即对称加密密钥算法,可选Blowfish、RC2、RC4 算法
        */
        public static final String SECRET_ALGORITHM = "Blowfish";
        /**
        * 密钥长度
        * 
        * ECDH算法默认密钥长度为256,其范围在112到571位之间
        */
        private static final int KEY_SIZE = 256;
        /**
        * 公钥
        */
        private static final String PUBLIC_KEY = “ECPublicKey”;
        /*
        * 私钥
        */
    private static final String PRIVATE_KEY = “ECPrivateKey”;
        /**
        * 初始化甲方密钥
        * 
        * @return Map 甲方密钥Map
        * @throws Exception
        */
        public static Map<String, Object>initKey() throws Exception {
            // 实例化密钥对生成器
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            // 初始化密钥对生成器
            keyPairGenerator.initialize(KEY_SIZE);
            // 生成密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 甲方公钥
            ECPublic KeypublicKey = (ECPublicKey) keyPair.getPublic();
            // 甲方私钥
            ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
            // 将密钥对存储在Map中
            Map<String, Object> keyMap = new HashMap<String, Object>(2);
            keyMap.put(PUBLIC_KEY, publicKey);
            keyMap.put(PRIVATE_KEY, privateKey);
            return keyMap;
        }
        /**
    * 初始化乙方密钥
        * 
        * @param key
        *      甲方公钥
        * @return Map 乙方密钥Map
        * @throws Exception
        */
        public static Map<String, Object>initKey(byte[] key) throws Exception {
            // 解析甲方公钥
            // 转换公钥材料
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
            // 实例化密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            // 产生公钥
            PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
            // 由甲方公钥构建乙方密钥
            ECParameterSpec ecParamSpec = ((ECPublicKey) pubKey).getParams();
            // 实例化密钥对生成器
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.
            getInstance(keyFactory.getAlgorithm());
            // 初始化密钥对生成器
            keyPairGenerator.initialize(ecParamSpec);
            // 产生密钥对
            KeyPair keyPair = keyPairGenerator.genKeyPair();
    // 乙方公钥
            ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
            // 乙方私钥
            ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
            // 将密钥对存储在Map中
            Map<String, Object>keyMap = new HashMap<String, Object>(2);
            keyMap.put(PUBLIC_KEY, publicKey);
            keyMap.put(PRIVATE_KEY, privateKey);
            return keyMap;
        }
        /**
        * 加密
        * 
        * @param data
        *      待加密数据
        * @param key
        *      密钥
        * @return byte[] 加密数据
        * @throws Exception
        */
        public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
            // 生成本地密钥
            SecretKey secretKey = new SecretKeySpec(key, SECRET_ALGORITHM);
            // 数据加密
            Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE,secretKey);
            return cipher.doFinal(data);
        }
        /**
        * 解密<br>
        * 
        * @param data
        *      待解密数据
        * @param key
        *      密钥
        * @return byte[] 解密数据
        * @throws Exception
        */
        public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
            // 生成本地密钥
            SecretKey secretKey = new SecretKeySpec(key, SECRET_ALGORITHM);
            // 数据解密
            Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            return cipher.doFinal(data);
        }
        /**
        * 构建密钥
        * 
        * @param publicKey
        *      公钥
        * @param privateKey
        *      私钥
        * @return byte[] 本地密钥
        * @throws Exception
    */
        public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey)
        throws Exception {
            // 实例化密钥工厂
            KeyFactorykeyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            // 初始化公钥
            // 密钥材料转换
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
            // 产生公钥
            PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
            // 初始化私钥
            // 密钥材料转换
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8
            EncodedKey Spec(privateKey);
            // 产生私钥
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
            // 实例化
            KeyAgreement keyAgree = KeyAgreement.getInstance
            (keyFactory.getAlgorithm());
            // 初始化
            keyAgree.init(priKey);
            keyAgree.doPhase(pubKey, true);
            // 生成本地密钥
            SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
            return secretKey.getEncoded();
        }
    
        /**
        * 取得私钥
        * 
        * @param keyMap
        *      密钥Map
        * @return byte[] 私钥
        * @throws Exception
        */
        public static byte[] getPrivateKey(Map<String, Object>keyMap)throws Exception {
            Key key = (Key) keyMap.get(PRIVATE_KEY);
            return key.getEncoded();
        }
    
        /**
        * 取得公钥
        * 
        * @param keyMap
        *      密钥Map
        * @return byte[] 公钥
        * @throws Exception
        */
        public static byte[] getPublicKey(Map<String, Object>keyMap)throws Exception {
            Key key = (Key) keyMap.get(PUBLIC_KEY);
            return key.getEncoded();
        }
    }
    
    

    上述代码与DH算法实现差别不大,请读者自行对比。测试用例如代码清单7-11所示。
    代码清单7-11 ECDH算法实现测试用例

    import static org.junit.Assert.*;
    import java.util.Map;
    import org.apache.commons.codec.binary.Base64;
    import org.junit.Before;
    import org.junit.Test;
    
    /**
     * ECDH校验
     * 
     * @author 梁栋
     * @version 1.0
     */
    public class ECDHCoderTest {
        /**
        * 甲方公钥
        */
        private byte[] publicKey1;
        /**
        * 甲方私钥
        */
        private byte[] privateKey1;
        /**
        * 甲方本地密钥
        */
        private byte[] key1;
        /**
        * 乙方公钥
        */
        private byte[] publicKey2;
        /**
        * 乙方私钥
        */
        private byte[] privateKey2;
        /**
        * 乙方本地密钥
        */
        private byte[] key2;
        /**
    * 初始化密钥
        * 
        * @throws Exception
        */
        @Before
        public final void initKey() throws Exception {
            // 生成甲方密钥对
            Map<String, Object> keyMap1 = ECDHCoder.initKey();
            publicKey1 = ECDHCoder.getPublicKey(keyMap1);
            privateKey1 = ECDHCoder.getPrivateKey(keyMap1);
            System.err.println("甲方公钥:\n" + Base64.encodeBase64String(publicKey1));
            System.err.println("甲方私钥:\n" + Base64.encodeBase64String(privateKey1));
            // 由甲方公钥产生本地密钥对
            Map<String, Object> keyMap2 = ECDHCoder.initKey(publicKey1);
            publicKey2 = ECDHCoder.getPublicKey(keyMap2);
            privateKey2 = ECDHCoder.getPrivateKey(keyMap2);
            System.err.println("乙方公钥:\n" + Base64.encodeBase64String(publicKey2));
            System.err.println("乙方私钥:\n" + Base64.encodeBase64String(privateKey2));
            key1 = ECDHCoder.getSecretKey(publicKey2,privateKey1);
            System.err.println("甲方本地密钥:\n" + Base64.encodeBase64String(key1));
            key2 = ECDHCoder.getSecretKey(publicKey1, privateKey2);
            System.err.println("乙方本地密钥:\n" + Base64.encodeBase64String(key2));
            // 校验
            assertArrayEquals(key1, key2);
        }
    
        /**
        * 校验
        * 
        * @throws Exception
        */
        @Test
        public final void test() throws Exception {
            System.err.println("\n=====甲方向乙方发送加密数据=====");
            String input1 = "密码交换算法”;
            System.err.println("原文: " + input1);
            System.err.println("---使用甲方本地密钥对数据加密---");
            // 使用甲方本地密钥对数据加密
            byte[] code1 = ECDHCoder.encrypt(input1.getBytes(), key1);
            System.err.println("加密: " + Base64.encodeBase64String(code1));
    System.err.println("---使用乙方本地密钥对数据解密---");
            // 使用乙方本地密钥对数据解密
            byte[] decode1 = ECDHCoder.decrypt(code1, key2);
            String output1 = (new String(decode1));
            System.err.println("解密: " + output1);
            assertEquals(input1, output1);
            System.err.println("\n=====乙方向甲方发送加密数据=====”);
            String input2 = "ECDH”;
            System.err.println("原文: " + input2);
            System.err.println("---使用乙方本地密钥对数据加密---");
            // 使用乙方本地密钥对数据加密
            byte[] code2 = ECDHCoder.encrypt(input2.getBytes(), key2);
            System.err.println("加密: " + Base64.encodeBase64String(code2));
            System.err.println("---使用甲方本地密钥对数据解密---");
            // 使用甲方本地密钥对数据解密
            byte[] decode2 = ECDHCoder.decrypt(code2, key1);
            String output2 = (new String(decode2));
            System.err.println("解密: " + output2);
            // 校验
            assertEquals(input2,output2);
        }
    }
    
    
    

    ECDH和DH算法使用流程一致,上述测试用例操作流程也一样。
    控制台对应输出如下双方公私钥以及本地密钥:
    甲方公钥:
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0E4OcYXDT1qTWiAsLovp0qFqmNFbYoA7FQc
    MRYLp7llwn/nThHs/EycWfAAsVk31tpgUWbSfriL9Y0pUE7eFsg==
    甲方私钥:
    MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg3fezhSzKiW+snx4rcYeDllF79tl
    JgJssjvXHtmS/dDugCgYIKoZIzj0DAQehRANCAATQTg5xhcNPWpNaICwui+nSoWqY0VtigDsVBwx
    FgunuWXCf+dOEez8TJxZ8ACxWTfW2mBRZtJ+uIv1jSlQTt4Wy
    乙方公钥:
    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+SHDmslF2cZShJ9qmZk4uODPdxZ8ZQQyoOb5GMLtN
    /9GXBJN0RkZoN2gZO94zbINvmMLxcmu7kCpbbOD4AirNg==
    乙方私钥:
    MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgo+t/0myl16mlpoaf2E7iH2FAF
    gJ+z+sM7nYsIUWuR4ygCgYIKoZIzj0DAQehRANCAAT5IcOayUXZxlKEn2qZmTi44M93FnxlBDKg
    5vkYwu03/0ZcEk3RGRmg3aBk73jNsg2+YwvFya7uQKlts4PgCKs2
    甲方本地密钥:
    HAXl7KzDUOX1B19Incsw/299Flg/RohMbGZMOGZEzaY=
    乙方本地密钥:
    HAXl7KzDUOX1B19Incsw/299Flg/RohMbGZMOGZEzaY=

    接下来甲乙双方互相传递加密数据:
    =====甲方向乙方发送加密数据=====
    原文: 密码交换算法
    ---使用甲方本地密钥对数据加密---
    加密: JG7kZbegknXj86EYYUz9cJXRcWH+Zc/G
    ---使用乙方本地密钥对数据解密---
    解密: 密码交换算法

    =====乙方向甲方发送加密数据=====
    原文: ECDH
    ---使用乙方本地密钥对数据加密---
    加密: 00Na9Qey/FU=
    ---使用甲方本地密钥对数据解密---
    解密: ECDH

    甲乙双方并没有交换本地密钥,同样可以完成数据的对称加密实现,这就是DH算法的精髓。
    7.3 典型非对称加密算法——RSA
            DH算法的诞生为后续非对称加密算法奠定了基础,较为典型的对称加密算法(如ElGamal、RSA和ECC算法等)都是在DH算法提出后相继出现的,并且其算法核心都源于数学问题。
            RSA算法基于大数因子分解难题,而ElGamal算法和ECC算法则是基于离散对数难题。
            目前,各种主流计算机语言都提供了对RSA算法的支持。在Java 7中,我们可以很方便地构建该算法。

    7.3.1 简述
           1978年,美国麻省理工学院(MIT)的Ron Rivest、Adi Shamir和Leonard Adleman三位学者提出了一种新的非对称加密算法,这种算法以这三位学者的姓氏开头字母命名,被称为RSA算法。
          RSA算法是唯一被广泛接受并实现的通用公开加密算法,目前已经成为非对称加密算法国际标准。不仅如此,RSA算法既可用于数据加密也可用于数字签名。我们熟知的电子邮件加密软件PGP就采用了RSA算法对数据进行加密/解密和数字签名处理。
    RSA算法将非对称加密算法推向了一个高潮,但它并不是没有缺点。相比DES以及其他对称加密算法而言,RSA算法要慢得多。作为加密算法,尤其是作为非对称加密算法的典型,针对RSA算法的破解自诞生之日起就从未停止过。
          1999年,RSA-155(512位)被成功因数分解,历时5个月。
           2002年,RSA-158也被成功因数分解。
          当然,基于大数因子分解数学难题的非对称加密算法仅有RSA算法这一种,但这不代表非对称加密算法除了RSA算法后继无人。基于离散对数问题的非对称加密算法包括ElGamal和ECC这两种算法,它们同样是优秀的非对称加密算法。

    7.3.2 实现
            Java 7提供了RSA算法实现,相关内容请读者朋友阅读第3章。RSA算法在理解上较之DH算法更为简单,在实现层面上也同样如此。
           RSA算法与DH算法在密钥管理和加密/解密两方面有所不同:一方面,甲方保留了私钥,而将公钥公布于乙方,甲乙双方密钥一一对应;另一方面,私钥用于解密,公钥则用于加密,反之亦然。
           这里要注意一点,在RSA算法中,公钥既可用于解密也可用于加密,私钥也是如此。但公钥加密的数据只能用私钥对其解密,而私钥加密的数据只能用公钥对其解密,这种对应关系是不能违背的。
          RSA算法实现较之DH算法实现较为简单,大部分内容与DH算法较为接近。与DH算法不同的是,RSA算法仅需要一套密钥即可完成加密/解密操作。Bouncy Castle对RSA算法做了相应扩充,增加了ISO9796-1Padding填充方式。
          有关RSA算法的Java 7实现与Bouncy Castle实现细节如下表所示。
                                                                              表 RSA算法

    完整实现如代码清单7-12所示。
    代码清单7-12 RSA算法实现

    import java.security.Key;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.HashMap;
    import java.util.Map;
    import javax.crypto.Cipher;
    /**
     * RSA安全编码组件
     * @version 1.0
     */
    public abstract class RSACoder {
      // 非对称加密密钥算法
      public static final String KEY_ALGORITHM = "RSA";
      // 公钥
      private static final String PUBLIC_KEY = "RSAPublicKey";
      // 私钥
      private static final String PRIVATE_KEY = "RSAPrivateKey";
      /**
      * RSA密钥长度 
      * 默认1024位,
      * 密钥长度必须是64的倍数, 
      * 范围在512~65536位之间。
      */
      private static final int KEY_SIZE = 512;
      /**
      * 私钥解密
      * @param data 待解密数据
    * @param key 私钥
      * @return byte[] 解密数据
      * @throws Exception
      */
      public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
         // 取得私钥
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 生成私钥
         PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
         // 对数据解密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, privateKey);
         return cipher.doFinal(data);
      }
      /**
      * 公钥解密
      * @param data 待解密数据
      * @param key 公钥
      * @return byte[] 解密数据
      * @throws Exception
      */
      public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
         // 取得公钥
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 生成公钥
         PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
         // 对数据解密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, publicKey);
         return cipher.doFinal(data);
      }
      /**
      * 公钥加密
      * @param data 待加密数据
      * @param key 公钥
      * @return byte[] 加密数据
      * @throws Exception
      */
      public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
         // 取得公钥
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
         // 对数据加密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
         return cipher.doFinal(data);
      }
      /**
      * 私钥加密
      * @param data 待加密数据
      * @param key 私钥
      * @return byte[] 加密数据
      * @throws Exception
      */
      public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {
         // 取得私钥
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 生成私钥
         PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
         // 对数据加密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, privateKey);
         return cipher.doFinal(data);
      }
      /**
      * 取得私钥
      * @param keyMap 密钥Map
      * @return byte[] 私钥
    * @throws Exception
      */
      public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {
         Key key = (Key) keyMap.get(PRIVATE_KEY);
         return key.getEncoded();
      }
      /**
      * 取得公钥
      * @param keyMap 密钥Map
      * @return byte[] 公钥
      * @throws Exception
      */
      public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {
         Key key = (Key) keyMap.get(PUBLIC_KEY);
         return key.getEncoded();
      }
      /**
      * 初始化密钥
      * @return Map 密钥Map
      * @throws Exception
      */
      public static Map<String, Object> initKey() throws Exception {
         // 实例化密钥对生成器
         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance (KEY_ALGORITHM); 
         // 初始化密钥对生成器
         keyPairGen.initialize(KEY_SIZE);
         // 生成密钥对
         KeyPair keyPair = keyPairGen.generateKeyPair();
         // 公钥
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
         // 私钥
         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
         // 封装密钥
         Map<String, Object> keyMap = new HashMap<String, Object>(2);
         keyMap.put(PUBLIC_KEY, publicKey);
         keyMap.put(PRIVATE_KEY, privateKey);
         return keyMap;
      }
    }
    
    
    

    RSA算法实现易于理解,对于RSA算法的测试只需要注意经公钥加密的数据是否可以通过私钥将其解密,反之,经私钥加密的数据是否可以通过公钥将其解密。完整的测试用例如代码清单7-13所示。
    代码清单7-13 RSA算法实现测试用例

    import static org.junit.Assert.*;
    import org.apache.commons.codec.binary.Base64;
    import org.junit.Before;
    import org.junit.Test;
    import java.util.Map;
    /**
     * RSA校验
     * @version 1.0
     */
    public class RSACoderTest {
      // 公钥
      private byte[] publicKey;
      // 私钥
      private byte[] privateKey;
      /**
      * 初始化密钥
    * @throws Exception
      */
      @Before
      public void initKey() throws Exception {
         // 初始化密钥
         Map<String, Object> keyMap = RSACoder.initKey();
         publicKey = RSACoder.getPublicKey(keyMap);
         privateKey = RSACoder.getPrivateKey(keyMap);
         System.err.println("公钥:\n" + Base64.encodeBase64String(publicKey));
         System.err.println("私钥:\n" + Base64.encodeBase64String(privateKey));
      }
      /**
      * 校验
      * @throws Exception
      */
      @Test
      public void test() throws Exception {
         System.err.println("\n---私钥加密--公钥解密---");
         String inputStr1 = "RSA加密算法";
         byte[] data1 = inputStr1.getBytes();
         System.err.println("原文:\n" + inputStr1);
         // 加密
         byte[] encodedData1 = RSACoder.encryptByPrivateKey(data1, privateKey);
    System.err.println("加密后:\n" + Base64.encodeBase64String (encodedData1));
         // 解密
         byte[] decodedData1 = RSACoder.decryptByPublicKey(encodedData1,
               publicKey);
         String outputStr1 = new String(decodedData1);
         System.err.println("解密后:\n" + outputStr1);
         // 校验
         assertEquals(inputStr1, outputStr1);
         System.err.println("\n---公钥加密--私钥解密---");
         String inputStr2 = "RSA Encypt Algorithm";
         byte[] data2 = inputStr2.getBytes();
         System.err.println("原文:\n" + inputStr2);
         // 加密
         byte[] encodedData2 = RSACoder.encryptByPublicKey(data2, publicKey);
         System.err.println("加密后:\n" + Base64.encodeBase64String (encodedData2));
         // 解密
         byte[] decodedData2 = RSACoder.decryptByPrivateKey(encodedData2,
               privateKey);
         String outputStr2 = new String(decodedData2);
         System.err.println("解密后: " + outputStr2);
         // 校验
    assertEquals(inputStr2, outputStr2);
      }
    }
    
    
    

    在控制台中输出了密钥的Base64编码信息,如下文所示:
    公钥: 
    MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ0PYlHiU439wWfWvQKMEgjjE/swks9KCG0UJy2qmSBs
    2e76f0eTswnNl7nFxbBr5TRRyl4EhkudWDIr0u6kBgcCAwEAAQ==
    私钥: 
    MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAnQ9iUeJTjf3BZ9a9AowSCOMT+zCS
    z0oIbRQnLaqZIGzZ7vp/R5OzCc2XucXFsGvlNFHKXgSGS51YMivS7qQGBwIDAQABAkAjMB4sEFP9
    /PtG43KHTpB/0zhXz8MklAadQaWhcpZKEB3LRINLH4jJ2UJxGWXMDS5nZtbG3/1jYd2Ee0bwGb7B
    AiEA8M/t/6MB4Yx4C4OBkd51TDByKJmKIEnFu2HSyzA6c2ECIQCm9zi9OuX2N/5rVytXfA+Oj7L1
    wetSOrGbEHXX3D/aZwIhAMRHJlyr13eoj5wK1ww2/vJXtmSjKPNCThl6FV8p8yphAiBVJyC44aEG
    wefvtrVUGOGWQ5Nx40Sw215ZRzvSq3GlYQIhALIHY3fxmLlEg3NC269ouFsYeTF/EO+M02+pazz+
    3UPv

    与DH算法不同,RSA算法仅需要一套密钥即可完成加密/解密操作,并且我们发现公钥的密钥长度明显小于私钥的密钥长度,更便于发送和携带。
    私钥加密公钥解密,如下所示:
    ---私钥加密--公钥解密---
    原文:
    RSA加密算法
    加密后:

    EePGm+yWtFvgSvc1pmh1hNoy3KyH0gssjc2FlvPSNkFAOOFOvvVIPQAmeRtTD+L3oUKUC61zQeqf
    N2B/t0ylxg==
    解密后:
    RSA加密算法
    反之,公钥加密私钥解密,如下所示:
    ---公钥加密--私钥解密---
    原文:
    RSA Encypt Algorithm
    加密后:
    hehNcGA8EGilNk3FJ7snGOU9XKGHN7t6DJlHQG9Ddi+h/xdk/IzWs3+SJfFsEnrTQe+96UvpEmF2
    atA7+Fndgw==
    解密后: RSA Encypt Algorithm

    RSA算法公钥长度远小于私钥长度,并遵循“公钥加密,私钥解密”和“私钥加密,公钥解密”这两项加密/解密原则。

    7.4 常用非对称加密算法——ElGamal
          在非对称加密算法中,几乎所有的算法都是基于数学问题而建立的:RSA算法基于大数因子分解数学难题,而ElGamal算法和ECC算法则基于离散对数问题。与典型非对称加密算法RSA算法相比,ElGamal算法则被称为常用非对称加密算法。

    7.4.1 简述
           1985年,Taher ElGamal提出了一种基于离散对数问题的非对称加密算法,该算法既可用于加密,又可用于数字签名,是除了RSA算法外最具有代表性的公钥加密算法之一。Taher ElGamal用自己的名字定义了这种算法——ElGamal算法。
           由于ElGamal算法具有较好的安全性,因此得到了广泛的应用。著名的美国数字签名标准(Digital Signature Standard,DSS)就是采用了ElGamal签名方案的一种变形——DSA(Digital Signature Algorithm)。ElGamal的一个不足之处是它的密文会成倍扩张。

    7.4.2 实现
            很遗憾,作为常用非对称加密算法的ElGamal算法并没有出现在Java 7的API中,但却包含在了Bouncy Castle的API中,弥补了Java语言缺少对ElGamal算法支持的缺憾。
          有关ElGamal算法的Bouncy Castle实现细节如表所示。
                                                                             表 ElGamal算法

     JCE框架为其他非对称加密算法实现提供了一个构建密钥对方式,均基于DH算法参数材料——DHParameterSpec类。代码清单7-14展示了如何构建ElGamal算法密钥对。
    代码清单7-14 构建ElGamal算法密钥对

    import java.security.Security;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    // 省略
    // 加入BouncyCastleProvider支持
    Security.addProvider(new BouncyCastleProvider());
    // 实例化算法参数生成器
    AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
    // 初始化算法参数生成器
    apg.init(KEY_SIZE);
    // 生成算法参数
    AlgorithmParameters params = apg.generateParameters();
    // 构建参数材料
    DHParameterSpec elParams = (DHParameterSpec) params.getParameterSpec(DHParameterSpec.class);
    // 实例化密钥对生成器
    KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
    // 初始化密钥对生成器
    kpg.initialize(elParams, new SecureRandom());
    // 生成密钥对
    KeyPair keys = kpg.genKeyPair();

    有了密钥对实例化对象keys自然就可以获得相应的密钥了。
    需要注意的是,这里我们使用Bouncy Castle提供的ElGamal算法实现,在使用各种引擎类做实例化操作前,需导入Bouncy Castle提供者,如代码清单7-15所示。
    代码清单7-15 导入Bouncy Castle提供者
    import java.security.Security;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    // 省略
    // 加入BouncyCastleProvider支持
    Security.addProvider(new BouncyCastleProvider());

    抛开密钥对的生成实现,ElGamal算法实现与RSA算法实现几乎一致,如代码清单7-16所示。
    代码清单7-16 ElGamal算法实现

    import java.security.AlgorithmParameterGenerator;
    import java.security.AlgorithmParameters;
    import java.security.Key;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.HashMap;
    import java.util.Map;
    import javax.crypto.Cipher;
    import javax.crypto.spec.DHParameterSpec;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    /**
     * ElGamal安全编码组件
    * @version 1.0
     * @since 1.0
     */
    public abstract class ElGamalCoder {
      // 非对称加密密钥算法
      public static final String KEY_ALGORITHM = "ElGamal";
      /**
      * 密钥长度
      * ElGamal算法
      * 默认密钥长度为1024
      * 密钥长度范围在160~16384位不等,
      * 且密钥长度必须是8的倍数。
      */
      private static final int KEY_SIZE = 256;
      // 公钥
      private static final String PUBLIC_KEY = "ElGamalPublicKey";
      // 私钥
      private static final String PRIVATE_KEY = "ElGamalPrivateKey";
      /**
      * 用私钥解密
      * @param data 待解密数据
      * @param key 私钥
      * @return byte[] 解密数据
      * @throws Exception
      */
      public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
         // 加入BouncyCastleProvider支持
         Security.addProvider(new BouncyCastleProvider());
         // 私钥材料转换
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
         // 实例化密钥工厂
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 生成私钥
         Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
         // 对数据解密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, privateKey);
         return cipher.doFinal(data);
      }
      /**
      * 用公钥加密
      * @param data 待加密数据
      * @param key 公钥
      * @return byte[] 加密数据
      * @throws Exception
      */
      public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
         // 加入BouncyCastleProvider支持
         Security.addProvider(new BouncyCastleProvider());
         // 公钥材料转换
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
         // 实例化密钥工厂
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 生成公钥
         Key publicKey = keyFactory.generatePublic(x509KeySpec);
         // 对数据加密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
         return cipher.doFinal(data);
      }
      /**
      * 生成密钥
      * @return Map 密钥Map
      * @throws Exception
      */
      public static Map<String, Object> initKey() throws Exception {
         // 加入BouncyCastleProvider支持
         Security.addProvider(new BouncyCastleProvider());
         // 实例化算法参数生成器
         AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance (KEY_ALGORITHM);
         // 初始化算法参数生成器
         apg.init(KEY_SIZE);
         // 生成算法参数
         AlgorithmParameters params = apg.generateParameters();
         // 构建参数材料
         DHParameterSpec elParams = (DHParameterSpec) params.getParameterSpec (DHParameterSpec.class);
         // 实例化密钥对生成器
         KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
         // 初始化密钥对生成器
         kpg.initialize(elParams, new SecureRandom());
         // 生成密钥对
         KeyPair keys = kpg.genKeyPair();
         // 取得密钥
         PublicKey publicKey = keys.getPublic();
         PrivateKey privateKey = keys.getPrivate();
         // 封装密钥
         Map<String, Object> map = new HashMap<String, Object>(2);
         map.put(PUBLIC_KEY, publicKey);
         map.put(PRIVATE_KEY, privateKey);
         return map;
      }
      /**
      * 取得私钥
      * @param keyMap 密钥Map
      * @return byte[] 私钥
      * @throws Exception
      */
      public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {
         Key key = (Key) keyMap.get(PRIVATE_KEY);
         return key.getEncoded();
      }
      /**
      * 取得公钥
      * @param keyMap
      * @return
      * @throws Exception
      */
      public static byte[] getPublicKey(Map<String, Object> keyMap)throws Exception {
         Key key = (Key) keyMap.get(PUBLIC_KEY);
         return key.getEncoded();
      }
    }
    
    
    

    ElGamal算法的测试用例与RSA算法测试用例较为相近。不同的是,ElGamal算法实现仅有“公钥加密,私钥解密”的部分。测试用例如代码清单7-17所示。
    代码清单7-17 ElGamal算法实现测试用例

    import static org.junit.Assert.*;
    import java.util.Map;
    import org.apache.commons.codec.binary.Base64;
    import org.junit.Before;
    import org.junit.Test;
    /**
     * ElGamal校验
     * @author 梁栋
     * @version 1.0
     */
    public class ElGamalCoderTest {
      // 公钥
      private byte[] publicKey;
      // 私钥
      private byte[] privateKey;
      /**
      * 初始化密钥
      * @throws Exception
      */
      @Before
      public void initKey() throws Exception {
         Map<String, Object> keyMap = ElGamalCoder.initKey();
         publicKey = ElGamalCoder.getPublicKey(keyMap);
         privateKey = ElGamalCoder.getPrivateKey(keyMap);
         System.err.println("公钥: \n" + Base64.encodeBase64String(publicKey));
         System.err.println("私钥: \n" + Base64.encodeBase64String(privateKey));
      }
      /**
      * 校验
      * @throws Exception
      */
      @Test
      public void test() throws Exception {
         String inputStr = "ElGamal加密";
         byte[] data = inputStr.getBytes();
         System.err.println("原文: \n" + inputStr);
         byte[] encodedData = ElGamalCoder.encryptByPublicKey(data, publicKey);
         System.err.println("加密后: \n" + Base64.encodeBase64String(encodedData));
         byte[] decodedData = ElGamalCoder.decryptByPrivateKey(encodedData, privateKey);
         String outputStr = new String(decodedData);
         System.err.println("解密后: \n" + outputStr);
         assertEquals(inputStr, outputStr);
      }
    }
    

    在控制台中的输出信息中,我们可以得到相应的公钥和私钥,代码如下所示:
    公钥: 
    MHcwUAYGKw4HAgEBMEYCIQCutlvZWBGgITJngn6hyMJ/VC/vt7K47W2p7QZdk+xpDwIhAKr3JJo1
    jqbZp0YJSeBceSDLL7fJOUATmOzEyXhv0kRcAyMAAiA6HMzcFJSyF78uBXzemyHNFbXOFF0plX15
    17p31YQqjQ==
    私钥: 
    MHkCAQAwUAYGKw4HAgEBMEYCIQCutlvZWBGgITJngn6hyMJ/VC/vt7K47W2p7QZdk+xpDwIhAKr3
    JJo1jqbZp0YJSeBceSDLL7fJOUATmOzEyXhv0kRcBCICIBecbEByJs28q7NH69zA2xDsjYbx9ihc
    IZSZzKO8z/Dn

    仔细观察,我们发现公钥和私钥的长度几乎是一致的。
    观察控制台的输出信息,加密/解密信息如下代码所示:
    原文: 
    ElGamal加密
    加密后: 
    T92lluoBzFrAkly8I6b9PX9MuuGTiUAcGmn4Zw+iNYozA1BtX/RkhLTtPzDobJQKLAUV3fLN7Jeq
    GZsgXC8gOA==
    解密后: 
    ElGamal加密

    ElGamal算法公钥和私钥长度几乎一致,基于Bouncy Castle加密组件的ElGamal算法实现仅遵循“公钥加密,私钥解密”的简单原则。

    7.5 实例:非对称加密网络应用
    目前,非对称加密算法(主要是RSA算法)主要应用于B2C、B2B等多种电子商务平台。但非对称加密算法并不直接对网络数据进行加密/解密,而是用于交换对称加密算法的秘密密钥。最终使用对称加密算法进行真正的加密/解密。
    此处,我们将对第7章的DataServer应用稍作修改,使用非对称加密算法RSA交换对称加密算法AES的秘密密钥,并使用该秘密密钥对数据进行加密/解密。
    对于前边用于实现DataServer应用的HttpUtils类和AESCoder类,本节不做详述,请读者阅读相关内容。此处,我们仅对DataServlet类和DataServlet类稍作修改,并增加用于RSA算法实现的RSACoder类。
    首先,我们要对本章中的RSACoder类稍作修改:使用开源组件Commons Codec的十六进制转换工具类Hex对密钥进行封装/解包。相关实现如代码清单7-18所示。
    代码清单7-18 密钥封装/解包

    import org.apache.commons.codec.binary.Hex;
    // 省略
    /**
     * 私钥加密
     * @param data 待加密数据
     * @param key 私钥
     * @return byte[] 加密数据
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {
      return encryptByPrivateKey(data, getKey(key));
    }
    /**
     * 公钥加密
     * @param data 待加密数据
     * @param key 公钥
     * @return byte[] 加密数据
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String key)
    throws Exception {
      return encryptByPublicKey(data, getKey(key));
    }
    /**
     * 私钥解密
     * @param data 待解密数据
     * @param key 私钥
     * @return byte[] 解密数据
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data, String key)
    throws Exception {
      return decryptByPrivateKey(data, getKey(key));
    }
    /**
     * 公钥解密
     * @param data 待解密数据
     * @param key 私钥
     * @return byte[] 解密数据
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {
      return decryptByPublicKey(data, getKey(key));
    }
    /**
     * 初始化密钥
     * @param keyMap 密钥Map
     * @return String 十六进制编码密钥
     * @throws Exception
     */
    public static String getPrivateKeyString(Map<String, Object> keyMap) throws Exception {
      return Hex.encodeHexString(getPrivateKey(keyMap));
    }
    /**
     * 初始化密钥
     * @param keyMap 密钥Map
     * @return String 十六进制编码密钥
     * @throws Exception
     */
    public static String getPublicKeyString(Map<String, Object> keyMap) throws Exception {
      return Hex.encodeHexString(getPublicKey(keyMap));
    }
    /**
     * 获取密钥
     * @param key 密钥
     * @return byte[] 密钥
     * @throws Exception
     */
    public static byte[] getKey(String key) throws Exception {
      return Hex.decodeHex(key.toCharArray());
    }
    
    

    在实际应用中,常常使用Base64或十六进制编码将密钥转为可见字符存储。十六进制编码要比Base64编码长度小得多,读者可以根据需要选择合适的算法。完整实现如代码清单7-19所示。
    代码清单7-19 RSACoder

    import java.security.Key;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.HashMap;
    import java.util.Map;
    import javax.crypto.Cipher;
    import org.apache.commons.codec.binary.Hex;
    /**
     * RSA安全编码组件
     * @version 1.0
     */
    public abstract class RSACoder {
      // 非对称加密密钥算法
      public static final String KEY_ALGORITHM = "RSA";
      // 公钥
      private static final String PUBLIC_KEY = "RSAPublicKey";
      // 私钥
      private static final String PRIVATE_KEY = "RSAPrivateKey";
      // RSA密钥长度默认1024位,密钥长度必须是64的倍数,范围在512~65536位之间。
      private static final int KEY_SIZE = 512;
      /**
      * 私钥解密
      * @param data 待解密数据
      * @param key 私钥
      * @return byte[] 解密数据
      * @throws Exception
      */
      public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {
         // 取得私钥
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 生成私钥
         PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
         // 对数据解密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, privateKey);
         return cipher.doFinal(data);
      }
      /**
      * 公钥解密
      * @param data 待解密数据
      * @param key 公钥
      * @return byte[] 解密数据
      * @throws Exception
      */
    public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
         // 取得公钥
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 生成公钥
         PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
         // 对数据解密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, publicKey);
         return cipher.doFinal(data);
      }
      /**
      * 公钥加密
      * @param data 待加密数据
      * @param key 公钥
      * @return byte[] 加密数据
      * @throws Exception
      */
      public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
         // 取得公钥
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
         // 对数据加密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
         return cipher.doFinal(data);
      }
      /**
      * 私钥加密
      * @param data 待加密数据
      * @param key 私钥
      * @return byte[] 加密数据
      * @throws Exception
      */
      public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {
         // 取得私钥
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         // 生成私钥
         PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
         // 对数据加密
         Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, privateKey);
         return cipher.doFinal(data);
      }
      /**
      * 取得私钥
      * @param keyMap 密钥Map
      * @return byte[] 私钥
      * @throws Exception
      */
      public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {
         Key key = (Key) keyMap.get(PRIVATE_KEY);
         return key.getEncoded();
      }
    /**
      * 取得公钥
      * @param keyMap 密钥Map
      * @return byte[] 公钥
      * @throws Exception
      */
      public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {
         Key key = (Key) keyMap.get(PUBLIC_KEY);
         return key.getEncoded();
      }
      /**
      * 初始化密钥
      * @return Map 密钥Map
      * @throws Exception
      */
      public static Map<String, Object> initKey() throws Exception {
         // 实例化密钥对生成器
         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
         // 初始化密钥对生成器
         keyPairGen.initialize(KEY_SIZE);
         // 生成密钥对
         KeyPair keyPair = keyPairGen.generateKeyPair();
         // 公钥
         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
         // 私钥
         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
         // 封装密钥
         Map<String, Object> keyMap = new HashMap<String, Object>(2);
         keyMap.put(PUBLIC_KEY, publicKey);
         keyMap.put(PRIVATE_KEY, privateKey);
         return keyMap;
      }
      /**
      * 私钥加密
      * @param data 待加密数据
      * @param key 私钥
      * @return byte[] 加密数据
      * @throws Exception
      */
      public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception {
         return encryptByPrivateKey(data, getKey(key));
      }
      /**
      * 公钥加密
      * @param data 待加密数据
      * @param key 公钥
      * @return byte[] 加密数据
      * @throws Exception
      */
      public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception {
         return encryptByPublicKey(data, getKey(key));
      }
      /**
      * 私钥解密
      * @param data 待解密数据
      * @param key 私钥
      * @return byte[] 解密数据
      * @throws Exception
      */
      public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception {
         return decryptByPrivateKey(data, getKey(key));
      }
      /**
      * 公钥解密
      * @param data 待解密数据
      * @param key 私钥
      * @return byte[] 解密数据
      * @throws Exception
      */
      public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception {
         return decryptByPublicKey(data, getKey(key));
      }
    /**
      * 初始化密钥
      * @param keyMap 密钥Map
    * @return String 十六进制编码密钥
      * @throws Exception
      */
      public static String getPrivateKeyString(Map<String, Object> keyMap) throws Exception {
         return Hex.encodeHexString(getPrivateKey(keyMap));
      }
      /**
      * 初始化密钥
      * @param keyMap 密钥Map
      * @return String 十六进制编码密钥
      * @throws Exception
      */
      public static String getPublicKeyString(Map<String, Object> keyMap) throws Exception {
         return Hex.encodeHexString(getPublicKey(keyMap));
      }
      /**
      * 获取密钥
      * @param key 密钥
      * @return byte[] 密钥
      * @throws Exception
      */
      public static byte[] getKey(String key) throws Exception {
         return Hex.decodeHex(key.toCharArray());
      }
    }
    
    
    

    通过调用RSACoder类的相关方法获得公钥和私钥,相关实现如代码清单7-20所示。
    代码清单7-20 RSACoder——构建密钥
    // 初始化密钥
    Map<String, Object> keyMap = RSACoder.initKey();
    // 获得并打印公钥
    String publicKey = RSACoder.getPublicKeyString(keyMap);
    System.err.println("publicKey - " + publicKey);
    // 获得并打印私钥
    String privateKey = RSACoder.getPrivateKeyString(keyMap);
    System.err.println("privateKey - " + privateKey);

    我们在控制台得到相应的公钥与私钥信息,我们将在后续实现中直接使用这些密钥。控制台密钥输出代码如下所示:
    publicKey- - 305c300d06092a864886f70d0101010500034b0030480241009fec6cff0209ef1a332a35ccafc2aae59c4d5275ef9186d73593186482ec637f6df042c2aa41115c8a1625a2e9e9f7844c008389e5a6379a268d877fd8edc2690203010001
    privateKey- - 30820153020100300d06092a864886f70d01010105000482013d308201390201000241009fec6cff0209ef1a332a35ccafc2aae59c4d5275ef9186d73593186482ec637f6df042c2aa41115c8a1625a2e9e9f7844c008389e5a6379a268d877fd8edc26902030100010240275ce73b214256b2e9331388ed1e0a3877ef6443991305d084e44ed5b68ffeb124274a17a3e3dd6e3013011c0602bb6efebebb5d327ebdf8052766f6d8be838d022100d372663308ab6e5c057bc5a56f9b9a16602e2872ded9344fa1dfbaadfb38d24b022100c19ed1dda201473d8fe6433fbfce1486d18782c837d30d4f122f81157a25ed9b0220047a6bc7b0eb508f0a5eb0b4ec4433633dee3c55127b2f2c70953872eedb293902204c451bb68a92a65581d1dabbc9fa8beb6fae49be44ff4646d78b0ef63edfa1f1022010d9524a9febc784bf8ad8dc07a15dee9f47744f9081599b0cc5e18fc37cee3f

    接下来,我们来调整DataSerlvet类。这里,我们使用RSA算法对请求的数据进行解密,获得本次交互的对称加密算法密钥。相关实现如代码清单7-21所示。
    代码清单7-21 DataServlet——解析密钥
    byte[] input = HttpUtils.requestRead(request);
    // 对秘密密钥解密
    String k = new String(RSACoder.decryptByPrivateKey(input, key));

    本文演示程序获得密钥后,使用AES算法将数据加密回复给请求方,相关实现如代码清单7-22所示。
    代码清单7-22 DataServlet——加密回复
    // 使用AES算法对数据加密并回复
    HttpUtils.responseWrite(response, AESCoder.encrypt(output, k));

    DataServlet类完整实现如代码清单7-23所示。
    代码清单7-23 DataServlet

    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    /**
     * 数据服务DataServlet
     * @author 梁栋
     * @since 1.0
     */
    public class DataServlet extends HttpServlet {
      private static final long serialVersionUID = -6219906900195793155L;
      // 密钥
      private static String key;
      // Servlet初始化参数--私钥
      private static final String KEY_PARAM = "key";
      // 初始化
      @Override
      public void init() throws ServletException {
         super.init();
         // 初始化密钥
         key = getInitParameter(KEY_PARAM);
      }
      // 处理POST请求
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         try {
             byte[] input = HttpUtils.requestRead(request);
             // 对秘密密钥解密
             String k = new String(RSACoder.decryptByPrivateKey(input, key));
             // 输出秘密密钥
             System.err.println(k);
             // 构造数据包
             StringBuilder sb = new StringBuilder();
             sb.append("<?xmi version=\"1.0\"encoding=]"UTF-8\"?>\r\n");
             sb.append("<dataGroup>\r\n");
             sb.append("\t<dataItem>\r\n");
             sb.append("\t\t<id>");
             sb.append("10201");
             sb.append("</id>\r\n");
             sb.append("\t\t<price>");
             sb.append("35.0");
             sb.append("</price>\r\n");
             sb.append("\t\t<time>");
             sb.append("2009-10-30");
             sb.append("</time>\r\n");
             sb.append("\t</dataItem>\r\n");
             sb.append("\t<dataItem>\r\n");
             sb.append("\t\t<id>");
             sb.append("10301");
             sb.append("</id>\r\n");
             sb.append("\t\t<price>");
             sb.append("55.0");
             sb.append("</price>\r\n");
             sb.append("\t\t<time>");
             sb.append("2009-10-31");
             sb.append("</time>\r\n");
             sb.append("\t</dataItem>\r\n");
             sb.append("</dataGroup>\r\n");
             byte[] output = sb.toString().getBytes();
             // 使用AES算法对数据加密并回复
             HttpUtils.responseWrite(response, AESCoder.encrypt(output, k));
             } catch (Exception e) {
                 throw new ServletException(e);
             }
      }
    }
    

    同时,我们需要修改web.xml文件,将私钥作为密钥变量配置在其中。完整实现如代码清单7-24所示。
    代码清单7-24 web.xml
     

    <?xml version="1.0" encoding="UTF-8"?>
    
      <display-name>DataServer</display-name>
      <servlet>
        <servlet-name>DataServlet</servlet-name>
        <servlet-class>DataServlet</servlet-class>
        <init-param>
          <param-name>key</param-name>
          <param-value>
    [CDATA[30820153020100300d06092a864886f70d01010105000482013d308201390201000241009fec6cff0209ef1a332a35ccafc2aae59c4d5275ef9186d73593186482ec637f6df042c2aa41115c8a1625a2e9e9f7844c008389e5a6379a268d877fd8edc26902030100010240275ce73b214256b2e9331388ed1e0a3877ef6443991305d084e44ed5b68ffeb124274a17a3e3dd6e3013011c0602bb6efebebb5d327ebdf8052766f6d8be838d022100d372663308ab6e5c057bc5a56f9b9a16602e2872ded9344fa1dfbaadfb38d24b022100c19ed1dda201473d8fe6433fbfce1486d18782c837d30d4f122f81157a25ed9b0220047a6bc7b0eb508f0a5eb0b4ec4433633dee3c55127b2f2c70953872eedb293902204c451bb68a92a65581d1dabbc9fa8beb6fae49be44ff4646d78b0ef63edfa1f1022010d9524a9febc784bf8ad8dc07a15dee9f47744f9081599b0cc5e18fc37cee3f]]>
          </param-value>
        </init-param>
      </servlet>
      <servlet-mapping>
        <servlet-name>DataServlet</servlet-name>
        <url-pattern>/DataServlet</url-pattern>
      </servlet-mapping>
    </web-app>
    

    最后,我们来调整测试用例DataServletTest类。
    此处,我们先通过AESCoder类initKeyString()方法构建秘密密钥,使用RSACoder对其加密并将其发送给服务器。相关实现如代码清单7-25所示。
    代码清单7-25 DataServletTest——构建秘密密钥
    /**
     * 公钥
     */
    private static final String publicKey =
    "305c300d06092a864886f70d0101010500034b0030480241009fec6cff0209ef1a332a35ccafc2aae59c4d5275ef9186d73593186482ec637f6df042c2aa41115c8a1625a2e9e9f7844c008389e5a6379a268d877fd8edc2690203010001";
    // 省略
    // 构建秘密密钥
    String secretKey = AESCoder.initKeyString();
    // 使用RSA算法加密并发送秘密密钥
    byte[] input = HttpUtils.postRequest(url,
    RSACoder.encryptByPublicKey(secretKey.getBytes(), publicKey));

    最后,我们使用AES算法对收到的数据进行解密,如代码清单7-26所示。
    代码清单7-26 DataServletTest——数据解密
    // 使用AES算法对数据解密
    String data = new String(AESCoder.decrypt(input, secretKey));

    完整实现如代码清单7-27所示。
    代码清单7-27 DataServletTest

    import static org.junit.Assert.*;
    import org.junit.Test;
    /**
     * DataServlet测试用例
     * @since 1.0
     */
    public class DataServletTest {
      // 公钥
      private static final String publicKey =
    "305c300d06092a864886f70d0101010500034b0030480241009fec6cff0209ef1a332a35ccafc2aae59c4d5275ef9186d73593186482ec637f6df042c2aa41115c8a1625a2e9e9f7844c008389e5a6379a268d877fd8edc2690203010001";
      // 请求地址
      private static final String url = "http://localhost:8080/dataserver/DataServlet";
      @Test
      public final void test() throws Exception {
         // 构建秘密密钥
         String secretKey = AESCoder.initKeyString();
         // 使用RSA算法加密并发送秘密密钥
         byte[] input = HttpUtils.postRequest(url, RSACoder.encryptByPublicKey (secretKey.getBytes(), publicKey));
         // 使用AES算法对数据解密
         String data = new String(AESCoder.decrypt(input, secretKey));
         System.err.println(data);
         // 校验
         assertNotNull(data);
      }
    }
    


    启动DataServer服务,执行DataServletTest测试方法。
    最终,我们可以在控制台得到由服务器下发的数据信息,代码如下所示:
    <?xml version="1.0" encoding="UTF-8"?>
    <dataGroup>
      <dataItem>
         <id>10201</id>
         <price>35.0</price>
         <time>2009-10-30</time>
      </dataItem>
      <dataItem>
         <id>10301</id>
         <price>55.0</price>
         <time>2009-10-31</time>
      </dataItem>
    </dataGroup>

          在实际应用中,我们很少会直接使用非对称加密算法进行数据加密。真正对数据进行加密的算法其实都是对称加密算法。非对称加密算法的主要职责是用来初始化对称加密算法的秘密密钥。
          对比第六部分代码实现,这里我们缺少了对于数据校验的部分。对于这项关键操作我们有两种选择:
          使用消息摘要算法对其数据进行摘要/验证。
          使用数字签名对其数据进行签名/验证。
          有关数字签名,以及对上述代码的改进我们将在下一部分涉及
          非对称加密算法通常配合数字证书、SSL/TLS协议构建单向认证或双向认证使用。

    展开全文
  • Java接口请求加密验签处理 最近做了一个接口的加密验签的功能,今天和大家分享一下***注(以下出现的参数字符串都是测试处理,方便大家理清思路,非真实正确的数据)*** 1、参数说明 字段名称:appcode(产品...
  • Java中常用的加密方式

    千次阅读 2017-12-28 14:27:22
    一、Java常用加密方式 Base64加密算法(编码方式) MD5加密(消息摘要算法,验证信息完整性) 对称加密算法 非对称加密算法 数字签名算法 数字证书 二、分类 按加密算法是否需要key被分为两类: 不基于key的有: Base64...
  • * RAS用来加密机密数据:密码/转账资金... * RAS非对唱加密Java实现: * 1.采用分组加密的方式,明文可以比较长,理论上无线长,但是太耗费时间 * 2. 不采用分组加密,直接整个元数据加密的话,每次最多加 117 bytes,
  •  Sun表示,在Java系统Web服务器内加密ECC将减少安全网上交易的时间。此外,通过实现与配有ECC设备之间的安全交易,ECC加密提高了Java系统Web服务器的安全性。 ECC采用较短的密钥,提供与传统替代方法等同级别的...
  • java加密与解密(一)

    万次阅读 多人点赞 2019-06-28 00:45:31
    纵观密码学的发展史,它共经历了三个阶段,分别是手工加密阶段、机械加密阶段和计算机加密阶段。手工加密阶段最为漫长,期间孕育了古典密码,这为后期密码学的发展奠定了基础。机械工业革命发展的同时促进着各种...
  • 由于没时间整理,直接贴出代码,不理解的请留言,谢谢。 package com.rocky.fintech.boss.util; import org.apache.commons.codec.binary.Hex; import java.security.MessageDigest; import java.util....
  • Java实现文件的加密与解密

    万次阅读 2019-04-17 09:20:49
     先对文件与加密的相关知识做一个极为简单的科普(知道的可以跳过)。 文件与字串 A、文件的操作流程一般为:打开–>读取–>对内容进行变换–>写入–>关闭。 B、常规性文件操作会用到的类有五个:File...
  • 利用java程序实现文件加密

    万次阅读 热门讨论 2019-07-18 20:31:22
    我们的文件在计算机中都是以二进制的形式存储,而Java中IO流(字节流和字符流)可以实现对底层文件的读取,故利用Java的IO流进行文件拷贝时,可以对底层二进制进行加密操作,随后通过解密操可以还原。 例如,我们对...
  • 辽 宁 工 业 大 学 JAVA程序设计 课程设计论文 题目 文件加密解密 院系 软件学院 专业班级 软件工程 学 号 学生姓名 指导教师 王彦华 教师职称 讲 师 起止时间 2012.6.18至2012.7.1 程序设计专题报告任务及评语 院系...
  • 一句话概括:Android没有使用标准Java的AES加密,而是自己实现了一套,顺便实现了 PKCS7Padding 。 PKCS5Padding可以解密PKCS7Padding加密的数据 从AES加密原理说起 加密流程 把明文按照128bit(16byte...
  • 严格地说,这种算法不能算是加密,因为理论上来说,它不能被解密。所以即使数据库丢失了,但是由于数据库里的密码都是密文,根本无法判断用户的原始密码,所以后果也不算太严重。 第三代密码 本来第二代密码设计...
  • java中文件如何加密压缩?

    千次阅读 2018-10-27 11:17:20
    在现如今已经可以实现大部分功能的互联网需求中,安全成为了需要的非必需品,工作需求中会遇到对导出的 excel 报表 做加密压缩的问题,今天有时间总结一下,我这里简单列举功能代码,连带其它代码文末会一并给出。...
  • Java实现AES加密

    2018-08-06 20:32:50
    AES:Advanced Encrypt Standard 高级加密标准。使用AES是为了代替原先的DES,现如今已被广泛使用。 相较于DES,使用56位秘钥,比较容易被破解。AES可以使用128、192和256位秘钥,并且使用128位分组加密和解密数据...
  • Android与Java服务端加密解密

    千次阅读 2015-08-10 15:28:21
    本篇博客是使用Android端与...在Android端做数据加密操作以前在做毕业设计的时候就想把这个功能加进去,奈何时间有限,知识有限再加上这个需求并没有那么迫切,时间一长就没有继续纠缠下去了。现如今,项目中要求加上
  • Java项目的加密问题

    千次阅读 2019-08-14 20:55:21
    随着Java越来越强大所以应用场景越来越丰富,应用的领域也越来越多,如果你遇到这种情况,项目要求自己公司开发,开发完成时要运行在其他公司(购买项目的公司)的服务器上,虽然我们将项目卖给他们,但是并不希望...
  • Java 前端加密传输后端解密以及验证码功能

    万次阅读 多人点赞 2016-07-20 10:32:51
    1. 加密解密 1.1 前端js加密概述 对系统安全性要求比较高,那么需要选择https协议来传输数据。当然很多情况下一般的web网站,如果安全要求不是很高的话,用http协议就可以了。在这种情况下,密码的明文传输显然...
  • Java中常用的加密方式(|)

    千次阅读 2020-07-30 17:18:06
    一、Java常用加密方式 Base64加密算法(编码方式) MD5加密(消息摘要算法,验证信息完整性) 对称加密算法 非对称加密算法 数字签名算法 数字证书 二、分类 按加密算法是否需要key被分为两类: 不基于key的有: ...
  • JAVA实现AES加密、解密

    万次阅读 多人点赞 2019-02-18 10:04:28
    高级加密标准(英语:Advanced Encryption Standard,缩写:AES),是一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。 那么为什么原来的DES会被取代呢,,原因就在于其使用56位...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 129,463
精华内容 51,785
关键字:

java时间加密

java 订阅