美文网首页
初窥Cipher源码,JCE框架的核心

初窥Cipher源码,JCE框架的核心

作者: Wayne维基 | 来源:发表于2019-12-25 11:07 被阅读0次

概要

最近再封装一个加密接口,类似RSA,于是决定深入研究一下Cipher这个Java的加密包。

RSA示例

网上copy的一段代码

    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
        // 加密后的字符串
        return encoder.encodeToString(encryptedData);
    }

几个关键过程:
1 获取算法
Cipher cipher = Cipher.getInstance("RSA");

2 算法初始化:
cipher.init(Cipher.ENCRYPT_MODE, publicKey);

3 分段加密:
RSA加密有长度限制
cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);

下面重点看下这几个方法吧

Cipher.getInstance

调用顺序

1 关键代码:Cipher getInstance(String var0)
-> List var1 = getTransforms(var0);
-> String[] var1 = tokenizeTransformation(var0);
-> StringTokenizer var3 = new StringTokenizer(var0, "/");
这个方法中去取真实的算法名称["RSA"]
为什么会有这个,网上搜了一下原来这个接口还有这种调用方式:
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
对应: “算法/模式/填充”

所以String[] var1 = tokenizeTransformation(var0);得到的可能是["算法",“模式”,“填充”]
对应的上层调用的方法getTransforms内部,就是根据是否有模式和填充算法分别做如下处理:
核心代码如下

if (var3 == null && var4 == null) {
    // 【无】 模式和填充参数
    Cipher.Transform var6 = new Cipher.Transform(var2, "", (String)null, (String)null);
    return Collections.singletonList(var6);
  } else {
    // 【有】 模式和填充参数
    ArrayList var5 = new ArrayList(4);
    var5.add(new Cipher.Transform(var2, "/" + var3 + "/" + var4, (String)null, (String)null));
    var5.add(new Cipher.Transform(var2, "/" + var3, (String)null, var4));
    var5.add(new Cipher.Transform(var2, "//" + var4, var3, (String)null));
    var5.add(new Cipher.Transform(var2, "", var3, var4));
    return var5;
  }

可以看出其中调用的: Cipher.Transform方法,就是根据模式和填充来组合Cipher.Transform对象,
如果只有算法参数,返回Collections.singletonList(var6)
如果有多个参数,返回一个ArrayList,其中用到了好多参数的组合,至于为什么这么组合,暂时不深究。

至此,我们看到了List var1 = getInstance(String var0)中第一行getTransforms(var0);所做的事情,继续往下。

var1中每一行是"算法",“模式”,“填充”,但是在下面的调用中
var1--> var2,var2 是在1的基础上转化成了service对象,简单来说就是var1,加上一个type属性编程service


image.png

然后通过下面这个语句,从 ProviderList中取到对应的服务。(provider是加密服务的注册地址,这个包中比较重要的一种方式,之后介绍。)
List var11 = GetInstance.getServices(var2);

得到了模式,算法,填充和服务之后,通过以下两种方式返回Cipher实例

 if (var8 == 2) {
        return new Cipher((CipherSpi)null, var6, var12, var0, var1);
      }

 try {
        CipherSpi var9 = (CipherSpi)var6.newInstance((Object)null);
        var7.setModePadding(var9);
        return new Cipher(var9, var6, var12, var0, var1);
      } catch (Exception var10) {
        var5 = var10;
      }

cipher.init(Cipher.ENCRYPT_MODE, publicKey);

因为是加密,所以Cipher.ENCRYPT_MODE = 1,其余可选数值

  public static final int DECRYPT_MODE = 2;
  public static final int WRAP_MODE = 3;
  public static final int UNWRAP_MODE = 4;
  public static final int PUBLIC_KEY = 1;
  public static final int PRIVATE_KEY = 2;
  public static final int SECRET_KEY = 3;

内部逻辑也是在选取provider,以及选择一些默认的padding,permission,,provider是这个包中提供的机制,一个provider对应一个已注册的算法的服务,这个模式暂时不深究

cipher.doFinal

doFinal(data.getBytes(), offset, inputLen - offset)
-> this.spi.engineDoFinal 一个抽象接口
-> engineDoFinal ,rsaCipher中找到实现类
-> this.doFinal();
-> RSACore.rsa(var1, this.publicKey);

注意一下,rsa算法加密长度限制要小于N的长度限制,
比如N是1024位,128字节,理论上原文长度限制128.

实际算法包的长度限制是117。网上资料是给padding预留11位。
RSAPadding类中代码上确实有相关的操作



但是maxDataSize字段也有其他的赋值方法,这里不深究各个条件下的长度限制了。

相关文章

网友评论

      本文标题:初窥Cipher源码,JCE框架的核心

      本文链接:https://www.haomeiwen.com/subject/esifoctx.html