Java加密体系(一)java.security包

一、JCA/ JCE

  • JCA(Java Cryptography Architecture) 是Java体系结构,提供了基本Java加密框架,比如证书、数字签名、消息摘要、秘钥对生成器等,在java.security包中实现。

  • JCE(Java Cryptography Extension)是JCA的扩展,主要负责提供DES、AES、RSA、DSA这样的加密算法,因为加密算法是会不断进步的,会有新的算法诞生,所以整个安全体系结构的可扩展性必须要得到保证。

  • JCE包因为其加密算法的安全限制,受美国出口限制,我们平时使用的是oracle提供的“阉割版”,比如默认不允许256位密钥的AES,我们通过oracle官网,可以下载“完整版”。
    下面是“完整版的加密扩展包”
    http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

  • 解压缩以后是这个样子:


    完整版加密扩展包.png

根据readme中的提示,放在<java-home>/lib/security包中就可以啦


image.png
  • JCE并不是只有oracle提供的,有多家厂商可以提供JCE的扩展包,在我们jdk的安装目录下的java.security文件中可以看到,支持的服务提供者Provider。


    Provider
  • JCA的实现是在java.security包下,这个包只能实现消息摘要算法,其他都要依赖JCE扩展包,在javax.crypto包中实现,也可以添加自己的provider,根据上图的格式继续填写第11个即可。使用Security.addProvider("xxx")可以完成Provider的添加,使用insertProviderAt("xxx", position)可以在指定位置完成添加,这里涉及到一个优先级的概念,如上图Provider所示,数字越小优先级越高。

  • 借用oracle官方的一个例子,如图privider example,我们可以使用如下代码获得摘要实例,比如我们要获取SHA-256算法生成摘要的实例,第一句代码会走左侧的图,遍历所有provider,获取到支持该算法的Provider就立刻返回,左侧会返回ProviderB,而生成摘要是提供重载方法的,可以指定Provider,第二行代码指定了ProviderC,那么就会直接返回ProviderC,可以看到使用方法简单灵活。

privider example
md = MessageDigest.getInstance("SHA-256");
md = MessageDigest.getInstance("SHA-256", "ProviderC");
  • 官方是不推荐使用Sun, SunJSSE,SunJCE,SunRsaSign这些厂商提供的Provider的,据说是因为历史原因导致这些厂商提供的功能和加密强度都不怎么样 。

  • MessageDigest.getInstance("SHA-256");这一行代码,的执行流程会是什么样子的呢?我们找到MessageDigest在包中位置,发现旁边还有一个和他的名字很像的SPI类,SPI全称是Service Provider Interface,是软件设计可插拔的体现,经常被用在插件的设计上。

  • 类似MessageDigest这样的类,我们通常叫做“engine”类,可以翻译叫做引擎类,每一个这样的引擎类都有一个对应的SPI类,引擎类继承SPI类,引擎类负责被用户调用,引擎类调用SPI类,我们发现所有的SPI类都是abstract的,也就是说SPI类提供模板,其他Provider实现SPI类中的方法就可以了,这些对于用户来说都是透明的,用户只需要在java.security中进行配置就可以了,是可插拔的一种体现,后面将会对这些引擎类进行简单介绍。


    MessageDigestSpi
  • 对于某些provider,可能会提供加密算法的别名,官方文档不推荐使用别名这种行为,因为其他厂商不一定叫这个别名。

  • 如果想知道自己可以使用那些Provider,Security的getProvider()方法可以获取到,获取到key有很多,笔者使用的是1.8版本,有600+条,如下面这段代码。

    public static void main(String[] args) {
      for (Provider p : Security.getProviders()) {
          System.out.println(p);
          for (Map.Entry entry :p.entrySet()) {
              System.out.println("\t"+entry.getKey());
          }
      }
    }
    

二、java.security包类库

  • 类似MessageDigest这样的类,我们通常叫做引擎类,java.包中的引擎类都是为其继承的SPI类服务,这样的可插拔的机制方便了整体的扩展,下面将介绍java.security包下的引擎类。

1、MessageDigest类

  • 可以使用MessageDigest生成指定加密算法的摘要,代码如下,首先根据MessageDigest的静态方法获取对应算法的实例,然后调用update()方法更新摘要,最后使用digest()方法生成摘要。

        MessageDigest digest =  MessageDigest.getInstance("SHA");
          digest.update(input);
          byte[] output = digest.digest();
    

2、Key接口

  • Key是一个接口,是秘钥的抽象概念,所有与秘钥相关的类都要实现这个接口,通过查看源代码我们可以发现这个接口继承了Serializable接口,这是因为秘钥多数情况都是在系统间进行传输,这个接口很简单只有三个方法,如下:

    public String getAlgorithm();//获取算法名称
    public String getFormat();//获取秘钥格式化的编码格式
    public byte[] getEncoded();//返回二进制格式的秘钥

  • 有三个接口继承了它:分别是SecretKey、PublicKey、PrivateKey,SecretKey是对称秘钥的抽象,对称加密算法的秘钥由SecretKey提供,PublicKey和PrivateKey对应非对称件加密算法中的公钥和私钥。

3、KeyPair接口

  • KeyPair是非对称加密算法秘钥对的抽象,如下图所示,这个类的构造方法参数只有两个,类型为PublicKey和PrivateKey,这个类是不提供公钥和私钥的setter方法的,只可以通过构造方法的方式去构造秘钥对。
KeyPair

4、KeyPairGenerator类

  • 秘钥对的生成就是由KeyPairGenerator来完成的,这是一个引擎类,同样也继承了SPI类,通过工厂方法getInstance()来完成秘钥对的构建,下面通过调用KeyPairGenerator的getInstance()方法获得实例,初始化秘钥长度,然后获得秘钥对。

     KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
      generator.initialize(1024);
      KeyPair keys = generator.generateKeyPair();
    

5、KeyFactory类

  • KeyFactory最大的作用就是根据指定的规范生成秘钥,如下面这段代码,使用的是PKCS8规范,这样的规范还有很多,如下图所示:

      PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
    
spec

6、Signature类

  • Signature类主要用于生成和验证数字签名,生成数字签名这一步我们通常称为“加签”,验证数字签名这一步,我们通常称为“验签”,首先我们根据KeyPairGenerator的工厂方法getInstance()获取实例秘钥对实例,初始化秘钥长度1024,生成秘钥对,根据指定算法构建Signature签名实例,根据私钥初始化,调用sign()方法完成加签,下面这一段代码展示了加签的过程:

      byte[] data = "Signature Data".getBytes();
      KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
      generator.initialize(1024);
      KeyPair keyPair = generator.generateKeyPair();
      Signature signature = Signature.getInstance(generator.getAlgorithm());
      signature.initSign(keyPair.getPrivate());
      signature.update(data);
      byte[] signData = signature.sign();
    
  • 验签过程和加签相似,使用公钥初始化,调用verify()方法完成验签,如下面代码所示:

      signature.initVerify(keyPair.getPublic());
      signature.update(data);
      boolean status = signature.verify(signData);
    

7、KeyStore类

  • KeyStore是秘钥库的抽象,用于管理秘钥和证书,这也是一个引擎类,如下代码,我们从本地加载秘钥库配合密码加载秘钥库,这里我们可以看到通过keyStore.aliases();获取了全部的别名列表,原因是keystore是通过别名去加载秘钥的,原理类似前面提到的Provider,获取到第一个别名返回。

       String keyPassword = "123456";
        inputStream = new FileInputStream(new File(keyPath));
        KeyStore keyStore = KeyStore.getInstance(keyType);
        keyStore.load(inputStream, keyPassword.toCharArray());
        Enumeration enum2 = keyStore.aliases();
        String keyAlias = null;
            if (enum2 == null) {
              return null;
             } else {
            if (enum2.hasMoreElements()) {
              keyAlias = (String) enum2.nextElement();
          } else {
              return null;
          }
      }
        PrivateKey priviteKey = keyStore.getKey(keyAlias, keyPassword.toCharArray());
    

参考:
1、oralce JCA参考指南:https://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/CryptoSpec.html#ProviderArch

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 148,637评论 1 318
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 63,443评论 1 266
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 99,164评论 0 218
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,075评论 0 188
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,080评论 1 266
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,365评论 1 184
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,901评论 2 283
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,649评论 0 176
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,122评论 0 223
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,734评论 2 225
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,093评论 1 236
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,548评论 2 222
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,028评论 3 216
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,765评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,291评论 0 178
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,162评论 2 239
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,293评论 2 242

推荐阅读更多精彩内容