Cipher类

Cipher类提供用于加密和解密的加密密码的功能。 加密是取数据(称为明文)和**的过程,并且产生对不知道**的第三方毫无意义的数据(密文)。 解密是相反的过程:取密文和**并产生明文。 
java网络学习之 jca 之cipha 引擎类介绍(14)

对称与非对称密码学

有两种主要类型的加密:对称(也称为**)和非对称(或公钥密码)。 在对称密码学中,同一个**既能加密也能解密数据。 保持**私密对保持数据保密至关重要。 另一方面,非对称加密使用公钥/私钥对来加密数据。 用一个**加密的数据与另一个**解密。 用户首先生成公钥/私钥对,然后将公钥发布在任何人都可以访问的可信数据库中。 希望与该用户安全通信的用户使用检索到的公钥来加密数据。 只有私钥的持有者才能解密。 保密私钥对此方案至关重要。

不对称算法(如RSA)通常比对称算法慢得多。 这些算法不能有效地保护大量的数据。 实际上,不对称算法被用来交换较小的秘***,用来初始化对称算法。

流加密与分组加密

有两种主要类型:块加密和流加密。 块加密(分组加密)一次处理整个块,通常是多个字节的长度。 如果没有足够的数据来创建完整的输入块,则必须填充数据:也就是说,在加密之前,必须添加虚拟字节以使密码块大小成倍数。 这些字节在解密阶段被剥离。 填充既可以由应用程序完成,也可以通过初始化密码来使用填充类型,例如“PKCS5PADDING”。 相比之下,流加密一次只能处理一个小单元(通常是一个字节,甚至一点点)的传入数据。 这允许密码处理任意数量的数据而不用填充。

操作模式

当使用简单的分组密码进行加密时,两个相同的明文块将总是产生相同的密文块。如果他们注意到重复文本块,那么试图**密文的密码分析者将会有更容易的工作。为了增加文本的复杂性,反馈模式使用前面的输出块在应用加密算法之前改变输入块。第一个块需要一个初始值,这个值被称为初始化向量(IV)。由于IV在加密之前只是简单地改变数据,所以IV应该是随机的,但不一定需要保密。有多种模式,例如CBC(密码块链接),CFB(密码反馈模式)和OFB(输出反馈模式)。 ECB(电子码本模式)是一种不受块位置或其他密文块影响的模式。因为如果ECB密文使用相同的明文/**,ECB密文是相同的,这种模式通常不适合加密应用,不应该使用。

一些算法如AES和RSA允许不同长度的**,但其他算法则是固定的,如3DES。 使用更长的**进行加密通常意味着对消息恢复的更强的抵抗力。 像往常一样,安全和时间之间有一个折衷,所以选择适当的**长度。

大多数算法使用二进制**。 即使以十六进制表示,大多数人类也无法记忆长序列的二进制数字。 字符密码更容易记忆。 由于字符密码通常是从少量字符中选择的(例如[a-zA-Z0-9]),因此已经定义了诸如“基于密码的加密”(PBE)等协议,这些协议使用字符密码并生成强二进制**。 为了使攻击者从口令到**的任务非常耗时(通过所谓的“字典式攻击”,其中常用字典字 - 值映射是预先计算的),大多数PBE实现将以随机数混合, 被称为盐,以增加关键的随机性。

更新的密码模式,例如带有关联数据的认证加密(AEAD)(例如,伽罗瓦/计数器模式(GCM)),可以对数据进行加密并同时验证结果信息。 在计算生成的AEAD标记(Mac)期间可以使用附加关联数据(AAD),但是这个AAD数据不会以密文的形式输出。 (例如,某些数据可能不需要保密,但应该计算标签计算以检测修改。)Cipher.updateAAD()方法可用于在标签计算中包含AAD。

使用GCM模式的AES密码

使用GCM的AES密码是一种AEAD密码,与非AEAD密码具有不同的使用模式。 除了常规数据外,还需要AAD,这是可选的加密/解密,但AAD必须在数据加密/解密之前提供。 另外,为了安全地使用GCM,调用者不应该重复使用**和IV组合来进行加密。 这意味着每次加密操作时,密码对象应该用不同的一组参数显式地重新初始化。

SecretKey myKey = ... ;
byte[] myAAD = ... ;
byte[] plainText = ... ;
int myTLen = ... ;
byte[] myIv = ... ;

GCMParameterSpec myParams = new GCMParameterSpec(myTLen, myIv); 
Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); 
c.init(Cipher.ENCRYPT_MODE, myKey, myParams); 
// AAD is optional, if present, it must be supplied before any update/doFinal calls. c.updateAAD(myAAD); // if AAD is non-null 
byte[] cipherText = new byte[c.getOutputSize(plainText.length)]; 
c.doFinal(plainText, 0, plainText.length, cipherText); // conclusion of encryption operation 
// To decrypt, same AAD and GCM parameters must be supplied c.init(Cipher.DECRYPT_MODE, myKey, myParams); 
c.updateAAD(myAAD); 
byte[] recoveredText = c.doFinal(cipherText); 
// MUST CHANGE IV VALUE if the same key were to be used again for encryption byte[] newIv = ...; 
myParams = new GCMParameterSpec(myTLen, newIv);
  • 创建Cipher对象

密码对象是通过使用密码getInstance()静态工厂方法之一获得的。 在这里,算法名称与其他引擎类稍有不同,因为它不仅指定算法名称,而且指定“变换”。 转换是一个字符串,它描述了在给定输入上执行的操作(或操作集)以产生一些输出。 变换总是包括密码算法的名称(例如,AES),并且可以跟随模式和填充方案。

转型的形式是:

  • “algorithm/mode/padding” or
  • “algorithm”

例如,以下是有效的转换:

    "AES/CBC/PKCS5Padding"

    "AES"

如果只指定了一个转换名称,系统将确定在环境中是否有所需的转换实现,如果有多个转换名称,则返回一个首选项。

如果同时指定了转换名称和包提供者,系统将确定所请求的包中是否存在所请求转换的实现,如果没有,则抛出异常。

建议使用完全指定算法,模式和填充的转换。 如果不这样做,提供者将使用默认值。 例如,SunJCE和SunPKCS11提供程序将ECB用作默认模式,将PKCS5Padding用作许多对称密码的默认填充。

这意味着在SunJCE提供商的情况下:

Cipher c1 = Cipher.getInstance("AES/ECB/PKCS5Padding");

Cipher c1 = Cipher.getInstance("AES");

是等同的语句。

**注意:**ECB模式是最简单的块密码模式,并且是JDK / JRE中的默认模式。 ECB适用于单个数据块,但绝对不应该用于多个数据块。

使用CFB和OFB等模式,分组密码可以以小于密码实际块大小的单位加密数据。 在请求这种模式时,可以通过在“AES / CFB8 / NoPadding”和“AES / OFB32 / PKCS5Padding”转换中将模式名称附加到模式名称来一次指定要处理的位数。 如果没有指定这样的号码,则使用提供者特定的默认值。 (例如,SunJCE提供程序使用默认值为128位的AES)。因此,可以使用8位模式(如CFB8或OFB8)将块密码转换为面向字节的流密码。

初始化Cipher对象

通过getInstance获得的Cipher对象必须初始化为四种模式之一,在Cipher类中定义为最终整数常量。 这些模式可以通过它们的符号名称来引用,这些符号名称将在下面显示,同时还会描述每种模式的用途:

ENCRYPT_MODE

数据加密.

DECRYPT_MODE

数据解密.

WRAP_MODE

将java.security.Key包装为字节,以便可以安全地传输**.

UNWRAP_MODE

将之前包装的**解包到java.security.Key对象中.

每个密码初始化方法都采用操作模式参数(opmode),并初始化该模式的密码对象。 其他参数包括包含**(certificate)的**(key)或证书,算法参数(params)以及随机源(random)。

要初始化Cipher对象,请调用以下init方法之一:

    public void init(int opmode, Key key);

    public void init(int opmode, Certificate certificate);

    public void init(int opmode, Key key, SecureRandom random);

    public void init(int opmode, Certificate certificate,
                     SecureRandom random);

    public void init(int opmode, Key key,
                     AlgorithmParameterSpec params);

    public void init(int opmode, Key key,
                     AlgorithmParameterSpec params, SecureRandom random);

    public void init(int opmode, Key key,
                     AlgorithmParameters params);

    public void init(int opmode, Key key,
                     AlgorithmParameters params, SecureRandom random);
  • 如果需要参数的密码对象(例如,初始化向量)被初始化为加密,并且没有参数提供给初始化方法,则底层密码实现本身应该提供所需的参数,或者通过生成随机参数或者通过使用 默认的,特定于提供者的参数集合。

但是,如果需要参数的Cipher对象被初始化为解密,并且没有参数提供给init方法,则将引发InvalidKeyException或InvalidAlgorithmParameterException异常,具体取决于所使用的init方法。

必须使用与加密相同的参数进行解密。

请注意,当一个Cipher对象被初始化时,它将失去所有先前获得的状态。 换句话说,初始化一个Cipher就相当于创建一个新的Cipher实例,并初始化它。 例如,如果密码首先被初始化为用给定**进行解密,然后初始化用于加密,则在解密模式下将失去获得的任何状态。

数据加解密

数据可以在一个步骤(单部分操作)或多个步骤(多部分操作)中加密或解密。 如果事先不知道数据将要运行多长时间,或者数据太长而无法一次存储在内存中,则多部分操作非常有用。

要在一个步骤中加密或解密数据,请调用其中一个doFinal方法:

    public byte[] doFinal(byte[] input);

    public byte[] doFinal(byte[] input, int inputOffset, int inputLen);

    public int doFinal(byte[] input, int inputOffset,
                       int inputLen, byte[] output);

    public int doFinal(byte[] input, int inputOffset,
                       int inputLen, byte[] output, int outputOffset)

要以多个步骤加密或解密数据,请调用其中一种更新方法:

    public byte[] update(byte[] input);

    public byte[] update(byte[] input, int inputOffset, int inputLen);

    public int update(byte[] input, int inputOffset, int inputLen,
                      byte[] output);

    public int update(byte[] input, int inputOffset, int inputLen,
                      byte[] output, int outputOffset)

多部分操作必须由上述doFinal方法之一终止(如果最后一步仍有一些输入数据),或者通过以下doFinal方法之一(如果没有输入数据留给最后一步):

    public byte[] doFinal();

    public int doFinal(byte[] output, int outputOffset);

如果填充(或非填充)已被请求作为指定转换的一部分,则所有doFinal方法都将处理任何必要的填充(或非填充)。

调用doFinal会将Cipher对象重置为通过调用init初始化时的状态。 也就是说,Cipher对象被重置并且可用于加密或解密(取决于在对init的调用中指定的操作模式)更多的数据。

封装和解包**

包装钥匙可以将钥匙从一个地方安全地转移到另一个地方。

wrap / unwrap API使得编写代码更方便,因为它直接处理关键对象。 这些方法还可以安全地传输基于硬件的**。

要包装一个Key,首先要为WRAP_MODE初始化Cipher对象,然后调用以下内容:

public final byte[] wrap(Key key);

如果您要将打包的**字节(调用wrap的结果)提供给打开它们的其他人,请务必发送收件人需要的附加信息,以便进行解包:

  • **算法的名称和
  • 包装**的类型(Cipher.SECRET_KEY,Cipher.PRIVATE_KEY或Cipher.PUBLIC_KEY之一)。

**算法名称可以通过从Key接口调用getAlgorithm方法来确定:

    public String getAlgorithm();

要打开先前调用的包装返回的字节,请首先初始化UNWRAP_MODE的Cipher对象,然后调用以下内容:

    public final Key unwrap(byte[] wrappedKey,
                            String wrappedKeyAlgorithm,
                            int wrappedKeyType));

这里,wrappedKey是从前一个包装调用返回的字节,wrappedKeyAlgorithm是与包装的关键字相关的算法,wrappedKeyType是包装的关键字的类型。 这必须是Cipher.SECRET_KEY,Cipher.PRIVATE_KEY或Cipher.PUBLIC_KEY之一。

管理算法参数

底层Cipher实现使用的参数(通过应用程序显式传递给init方法或由底层实现本身生成)可以通过调用其getParameters方法从Cipher对象中检索,该方法将参数作为java返回 .security.AlgorithmParameters对象(如果没有使用参数,则返回null)。 如果参数是初始化向量(IV),则也可以通过调用getIV方法来检索。

在以下示例中,实现基于密码的加密(PBE)的Cipher对象仅使用一个键而没有参数进行初始化。 但是,所选择的基于密码的加密算法需要两个参数 - 一个salt和一个迭代计数。 这些将由底层算法实现本身生成。 应用程序可以从Cipher对象中检索生成的参数,如下所示:

    import javax.crypto.*;
    import java.security.AlgorithmParameters;

    // get cipher object for password-based encryption
    Cipher c = Cipher.getInstance("PBEWithHmacSHA256AndAES_256");

    // initialize cipher for encryption, without supplying
    // any parameters. Here, "myKey" is assumed to refer
    // to an already-generated key.
    c.init(Cipher.ENCRYPT_MODE, myKey);

    // encrypt some data and store away ciphertext
    // for later decryption
    byte[] cipherText = c.doFinal("This is just an example".getBytes());

    // retrieve parameters generated by underlying cipher
    // implementation
    AlgorithmParameters algParams = c.getParameters();

    // get parameter encoding and store it away
    byte[] encodedAlgParams = algParams.getEncoded();

必须使用与加密相同的参数进行解密。 它们可以从它们的编码实例化,并用于初始化相应的Cipher对象进行解密,如下所示:

    import javax.crypto.*;
    import java.security.AlgorithmParameters;

    // get parameter object for password-based encryption
    AlgorithmParameters algParams;
    algParams = AlgorithmParameters.getInstance("PBEWithHmacSHA256AndAES_256");

    // initialize with parameter encoding from above
    algParams.init(encodedAlgParams);

    // get cipher object for password-based encryption
    Cipher c = Cipher.getInstance("PBEWithHmacSHA256AndAES_256");

    // initialize cipher for decryption, using one of the
    // init() methods that takes an AlgorithmParameters
    // object, and pass it the algParams object from above
    c.init(Cipher.DECRYPT_MODE, myKey, algParams);
  • 如果在初始化Cipher对象时没有指定任何参数,并且您不确定底层实现是否使用任何参数,则可以通过简单地调用Cipher对象的getParameters方法并检查返回的值来找到。 返回值为null表示没有使用参数。

SunJCE提供者实现的以下密码算法使用参数:

  • AES,DES-EDE和Blowfish在使用反馈(即CBC,CFB,OFB或PCBC)模式时,使用初始化向量(IV)。 javax.crypto.spec.IvParameterSpec类可用于使用给定的IV初始化Cipher对象。
  • PBE密码算法使用一组参数,包括盐和迭代计数。 javax.crypto.spec.PBEParameterSpec类可用于初始化实现PBE算法的Cipher对象(例如:PBEWithHmacSHA256AndAES_256),并使用给定的salt和迭代次数。

请注意,如果使用SealedObject类,则不必担心存储或传输解密操作使用的任何算法参数。 该类将用于密封(加密)的参数附加到加密的对象内容,并使用相同的参数来解密(解密)。

加密输出注意事项

一些Cipher的更新和doFinal方法允许调用者指定要将数据加密或解密的输出缓冲区。 在这些情况下,传递足够大的缓冲区来保存加密或解密操作的结果是很重要的。

密码中的以下方法可用于确定输出缓冲区的大小:

  public int getOutputSize(int inputLen)

其他基于Cipher的类

有一些帮助程序类在内部使用密码提供方便的访问常见的密码使用。

CipherInputStream类

这个类是一个FilterInputStream,用于加密或解密通过它的数据。 它由一个InputStream或其一个子类和一个Cipher组成。 CipherInputStream表示一个安全的输入流,一个Cipher对象被插入到其中。 CipherInputStream的读取方法返回从底层InputStream中读取的数据,但是嵌入的Cipher对象已经处理了额外的数据。 Cipher对象在被CipherInputStream使用之前必须完全初始化。

例如,如果嵌入式密码已经被初始化为解密,则CipherInputStream会在将它们返回到应用程序之前尝试解密从底层InputStream中读取的数据。

该类严格遵守其祖先类java.io.FilterInputStream和java.io.InputStream的语义,特别是失败语义。 这个类具有在祖先类中指定的那些方法,并覆盖它们全部,以便数据由嵌入式密码进行额外处理。 此外,这个类捕获所有祖先类不抛出的异常。 特别是skip(long)方法只会跳过已经被Cipher处理过的数据。

使用这个类的程序员不要使用在这个类中没有定义或重写的方法(比如一个新的方法或稍后添加到其中一个超类的构造函数),这是非常重要的,因为这些方法的设计和实现 不太可能考虑对CipherInputStream的安全影响。

作为使用的一个例子,假设cipher1已经被初始化用于加密。 下面的代码演示了如何使用包含该密码和FileInputStream的CipherInputStream来加密输入流数据:

    FileInputStream fis;
    FileOutputStream fos;
    CipherInputStream cis;

    fis = new FileInputStream("/tmp/a.txt");
    cis = new CipherInputStream(fis, cipher1);
    fos = new FileOutputStream("/tmp/b.txt");
    byte[] b = new byte[8];
    int i = cis.read(b);
    while (i != -1) {
        fos.write(b, 0, i);
        i = cis.read(b);
    }
    fos.close();

上面的程序从文件/tmp/a.txt中读取和加密内容,然后将结果(加密字节)存储在/tmp/b.txt中。

以下示例演示如何轻松连接CipherInputStream和FileInputStream的多个实例。 在这个例子中,假设cipher1和cipher2已分别被加密和解密初始化(使用相应的**)。

    FileInputStream fis;
    FileOutputStream fos;
    CipherInputStream cis1, cis2;

    fis = new FileInputStream("/tmp/a.txt");
    cis1 = new CipherInputStream(fis, cipher1);
    cis2 = new CipherInputStream(cis1, cipher2);
    fos = new FileOutputStream("/tmp/b.txt");
    byte[] b = new byte[8];
    int i = cis2.read(b);
    while (i != -1) {
        fos.write(b, 0, i);
        i = cis2.read(b);
    }
    fos.close();

上面的程序将文件/tmp/a.txt中的内容复制到/tmp/b.txt中,除了内容首先被加密,然后在从/tmp/a.txt读取内容时解密。 当然,因为这个程序只是简单地加密文本并立即解密,实际上它并不是非常有用,除非作为一个简单的方式来说明CipherInputStreams的链接。

请注意,CipherInputStream的读取方法将阻塞,直到从底层密码返回数据。 如果使用分组密码,则必须从底层的InputStream获得完整的密文块。

CipherOutputStream类

这个类是FilterOutputStream,用于加密或解密通过它的数据。 它由一个OutputStream或其一个子类和一个Cipher组成。 CipherOutputStream表示一个安全的输出流,一个Cipher对象插入其中。 CipherOutputStream的写入方法首先使用嵌入的Cipher对象处理数据,然后将它们写出到底层的OutputStream中。 Cipher对象在被CipherOutputStream使用之前必须完全初始化。

例如,如果嵌入式密码已经被初始化为加密,那么CipherOutputStream会在将数据写出到底层输出流之前对其数据进行加密。

该类严格遵守其祖先类java.io.OutputStream和java.io.FilterOutputStream的语义,特别是失败语义。 这个类具有在其祖先类中指定的方法,并覆盖它们全部,以便所有数据都由嵌入式密码额外处理。 此外,这个类捕获所有祖先类不抛出的异常。

使用这个类的程序员不要使用在这个类中没有定义或重写的方法(比如一个新的方法或稍后添加到其中一个超类的构造函数),这是非常重要的,因为这些方法的设计和实现 不太可能考虑对CipherOutputStream的安全影响。

作为使用的一个例子,假设cipher1已经被初始化用于加密。 下面的代码演示了如何使用包含该密码和FileOutputStream的CipherOutputStream来加密要写入输出流的数据:

    FileInputStream fis;
    FileOutputStream fos;
    CipherOutputStream cos;

    fis = new FileInputStream("/tmp/a.txt");
    fos = new FileOutputStream("/tmp/b.txt");
    cos = new CipherOutputStream(fos, cipher1);
    byte[] b = new byte[8];
    int i = fis.read(b);
    while (i != -1) {
        cos.write(b, 0, i);
        i = fis.read(b);
    }
    cos.flush();

上面的程序从文件/tmp/a.txt中读取内容,然后将结果(加密字节)加密并存储在/tmp/b.txt中。

以下示例演示如何轻松连接CipherOutputStream和FileOutputStream的多个实例。 在这个例子中,假设cipher1和cipher2已分别被初始化用于解密和加密(使用相应的**):

    FileInputStream fis;
    FileOutputStream fos;
    CipherOutputStream cos1, cos2;

    fis = new FileInputStream("/tmp/a.txt");
    fos = new FileOutputStream("/tmp/b.txt");
    cos1 = new CipherOutputStream(fos, cipher1);
    cos2 = new CipherOutputStream(cos1, cipher2);
    byte[] b = new byte[8];
    int i = fis.read(b);
    while (i != -1) {
        cos2.write(b, 0, i);
        i = fis.read(b);
    }
    cos2.flush();
  • 上述程序将文件/tmp/a.txt中的内容复制到/tmp/b.txt中,除了内容先被加密,然后在写入/tmp/b.txt之前将其解密。

使用分组密码算法时需要注意的一点是,在将数据加密并发送到底层输出流之前,必须给CipherOutputStream一个完整的明文数据块。

在这个类的flush和close方法之间还有一个其他的重要区别,如果被封装的密码对象实现了一个开启了padding的分组密码算法,它变得更加相关:

  • flush刷新底层OutputStream,方法是强制所有已被封装的Cipher对象处理的缓冲输出字节被写出。 封装的密码对象缓冲的任何字节,并等待被它处理,不会被写出。

 

 

 

 

附录1:加密算法分类:

流加密(stream cipher)

加密和解密双方使用相同伪随机加密数据流(即**),一般都是逐位异或或者随机置换数据内容,常见的流加密算法如RC4。

流加密中,**的长度和明文的长度是一致的。假设明文的长度是n 比特,那么**也为n比特。因此暴力**流密码是很难的。

加解密过程:

明文P和密文S通过**K和异或操作进行转换。 

P⊕K=SP⊕K=S

S⊕K=PS⊕K=P

 

关键技术

流密码的关键技术在于设计一个良好的##**流生成器##,即由种子**通过**流生成器生成伪随机流。 
通信双方交换种子**即可(已拥有相同的**流生成器)。

分组加密(block cipher)

也叫块加密,将明文分成多个等长的模块(block),使用确定的算法和对称**对每组分别加密解密。

附录2:加密模式分类:

加密模式

对称算法有以下5种加密模式,对称/分组密码一般分为流加密(如OFB、CFB等)和块加密(如ECB、CBC等)

加密模式(英文名称及简写) 中文名称 特点
Electronic Code Book(ECB) 电子密码本模式 简单快速,可并行计算
Cipher Block Chaining(CBC) 密码分组链接模式 仅解密支持并行计算
Cipher Feedback Mode(CFB) 加密反馈模式 仅解密支持并行计算
Output Feedback Mode(OFB) 输出反馈模式 不支持并行运算
Counter (CTR) 计算器模式 支持并行计


ECB

ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加***长度相同,然后每组都用相同的**进行加密。

相同的明文会产生相同的密文。 
其缺点是:电子密码本模式用一个**加密消息的所有块,如果原消息中重复明文块,则加密消息中的相应密文块也会重复。 
因此,电子密码本模式适于加密小消息。

java网络学习之 jca 之cipha 引擎类介绍(14)

CBC

需要初始化向量IV(长度与分组大小相同)参与计算第一组密文,第一组的密文与第二组数据XOR计算后再进行加密产生第二组密文 。

安全性较好,TLS、IPSec等标准的推荐模式,但不利于并行运算。 
加密运算不支持并行,解密运算支持并行。

java网络学习之 jca 之cipha 引擎类介绍(14) 
java网络学习之 jca 之cipha 引擎类介绍(14)

CFB

面向字符的应用程序的加密要使用流加密法,可以使用加密反馈模式。在此模式下,数据用更小的单元加密,如可以是8位,这个长度小于定义的块长(通常是64位)。其加密步骤是: 
1、使用length位的初始化向量。初始化向量放在移位寄存器中,在第一步加密,产生相应的length位初始化密文K; 
2、初始化密文K高n位与明文前n位进行异或运算,产生密文第一部分c(密文块0),然后将c传输到接收方; 
3、向量的位(即初始化向量所在的移位寄存器内容)左移n位,在移位寄存器最右边的n位填入c的内容,使其为不可预测的数据; 
4、重复第1-3步,直到加密所有的明文单元。

仅解密支持并行计算

java网络学习之 jca 之cipha 引擎类介绍(14)

OFB

输出反馈模式与CFB相似,惟一差别是,CFB中密文填入加密过程下一阶段,而在OFB中,初始化向量加密过程的输出K的高n位填入加密过程下一阶段。

可事先进行加密、解密的准备,将分组密码转化为流模式。

不支持并行运算。

java网络学习之 jca 之cipha 引擎类介绍(14)

 

CTR

计算器模式(Counter (CTR))不常见,在CTR模式中, 有一个自增的算子,这个算子用**加密之后的输出和明文异或的结果得到密文,相当于一次一密。这种加密方式简单快速,安全可靠,而且可以并行加密。支持并行计算

java网络学习之 jca 之cipha 引擎类介绍(14)

 

相关文章:

  • 2021-12-02
  • 2022-12-23
  • 2021-11-03
  • 2022-01-01
  • 2021-06-29
  • 2021-11-30
  • 2021-06-20
猜你喜欢
  • 2021-04-19
  • 2021-09-25
  • 2021-09-17
  • 2021-09-16
  • 2021-06-28
  • 2021-12-28
相关资源
相似解决方案