摘要: 针对不同平台环境下加解密的互通问题,结合Java平台下密码扩展服务SunJCE提供的加密类函数Cipher,对加密算法中使用到的明文填充方式进行阐述。详细介绍加密时明文数据的常用填充规则,并比较数据填充前后的区别,深入分析SunJCE支持的填充方式与常用填充规则的对应性,并对RSA算法的加解密互通进行了测试。加密数据填充方式的研究,为Java平台与其他平台之间加解密参数的约定提供了依据。双方只有遵循相同的填充和去填充规则,才能实现有效的解密。
关键词:核心期刊论文发表代理,SunJCE,Cipher,加密模式,填充
Study on mode and padding in encryption algorithm
FAN Zhi?ying
(The First Research Institute of Ministry of Public Security of P.R.C, Beijing 100048, China)
Abstract: Aiming at the interoperability of encryption and decryption in different platform environment, the two important parameters which are encryption mode and padding method used in encryption algorithm are elaborated in combination with encryption function Cipher provided by the encryption extended service on the Java platform. The rules in the encryption mode are discussed in detail, and their advantages, disadvantages and application scope are compared. The difference between the plaintext data before and after padding is analyzed in depth, which can narrow the range of encryption and decryption parameters for Java and other platforms, and can effectively solve the interaction problem between encryption and decryption.
Keywords: SunJCE; Cipher; encryption mode; padding
0 引 言
对网络中传输的信息进行加密,可以有效地保护重要信息和敏感信息的安全。但是在计算机软件开发中,编程语言种类繁多,虽然都提供标准算法的支持,但如果没有统一加密算法中的参数,不同语言环境下的通信双方往往不能正确解密。一般情况下,使用不同语言开发的双方只有约定加密模式和明文填充方式,保证字节序列相同,保证密钥的生成方式与编码相同,使用相同字符编解码方式等,才可以保证加解密双方的互通。本文主要结合Sun公司的Java加密扩展(Java Cryptography Extension,SunJCE)服务提供的加密类―Cipher,对加密模式和明文填充方式这两个重要参数的进行了深入分析,为加解密参数约定提供参考。
1 加密类Cipher参数分析
使用Java编程实现时,SunJCE提供的加密类Cipher包含了多种公开的对称和非对称加密算法。为了创建Cipher对象,需要调用Cipher类的getInstance方法,并传递一个transformation参数。其中在获取cipher实例的时候使用的API为:
static Cipher getInstance(String transformation, String provider)
其中provider的名称是可选参数,默认为SunJCE提供者。transformation的格式为:“algorithm/mode/padding”。表1详细列出了transformation的参数,后节主要针对下表中的填充方式进行深入分析[1]。
2 填充方式
从表1可以看出,SunJCE加密算法中提供的模式有:电子密码本模式(ECB)、密码分组链接模式(CBC)、密码反馈模式(CFB)、输出反馈模式(OFB)、计数器模式(CTR)、密码文本盗用模式(CTS)、扩散密码分组链接模式(PCBC),还有一种模式为NONE,它表示在加解密过程中不使用任何模式。由于不同平台和不同编程语言遵循的加密模式具有一致的定义,因此只要加解密双方按照协商指定模式进行加解密即可。
表1 SunJCE Provider支持的Cipher的详细信息
而对数据在加密时进行填充、解密时去除填充则是通信双方需要重点考虑的因素。对原文进行填充,主要基于以下原因:首先,考虑安全性。由于对原始数据进行了填充,使原文能够“伪装”在填充后的数据中,使得攻击者很难找到真正的原文位置。其次,由于块加密算法要求原文数据长度为固定块大小的整数倍,如果加密原文不满足这个条件,则需要在加密前填充原文数据至固定块大小的整数倍。另外,填充也为发送方与接收方提供了一种标准的形式以约束加密原文的大小[2]。只有加解密双方知道填充方式,才可知道如何准确移去填充的数据并进行解密。 2.1 常用填充方式
常用的填充方式至少有5种[3],不同编程语言实现加解密时用到的填充多数来自于这些方式或它们的变种方式。
(1) 填充数据为填充字节序列的长度
这种填充方式中,填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。假定块长度为8,原文数据长度为9,则填充字节数等于0x07;如果明文数据长度为8的整数倍,则填充字节数为0x08。填充字符串如下:
原文数据1:FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 08 08 08 08 08 08 08 08
(2) 填充数据为0x80后加0x00
这种填充方式中,填充字符串的第一个字节数是0x80,后面的每个字节是0x00。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:
原文数据1:FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00 00
(3) 填充数据的最后一个字节为填充字节序列的长度
这种填充方式中,填充字符串的最后一个字节为该字节序列的长度,而前面的字节可以是0x00,也可以是随机的字节序列。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:
原文数据1:FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07或FF FF FF FF FF FF FF FF FF 58 B3 98 9B AD F4 07
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 08或FF FF FF FF FF FF FF FF 32 58 B3 98 9B AD F4 08
(4) 填充数据为空格
这种填充方式中,填充字符串的每个字节为空格对应的字节数0x20。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:
原文数据1:FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 20 20 20 20 20 20 20
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 20 20 20 20 20 20 20 20
(5) 填充数据为0x00
这种填充方式中,填充字符串的每个字节为0x00。假定块长度为8,原文数据长度为9或者为8的整数倍,则填充字符串如下:
原文数据1:FF FF FF FF FF FF FF FF FF
填充后数据1:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
原文数据2:FF FF FF FF FF FF FF FF
填充后数据2:FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00
在填充方式(4)和方式(5)中,由于缺少填充数据长度的标识信息,如果原文数据的后几个字节本身包括空格或0,将不能够准确移去填充的数据。
因此使用这样的填充方式时,对原文数据有一定的要求。
2.2 SunJCE支持的填充方式
从表1可以看出,SunJCE Provider支持的填充方式有:ISO10126Padding,PKCS5Padding(或PKCS7Padding),PKCS1Padding,OAEPWithAndPadding。
(1) ISO10126Padding
ISO10126Padding填充方式在W3C推荐标准“XML Encryption Syntax and Processing”中有详细描述[4]。它与2.1节填充方式(3)相对应。
(2) PKCS5Padding
PKCS5Padding或PKCS7Padding是RSA公司的公钥密码学标准[5]――PKCS #5文档中定义的填充方式。它与2.1节填充方式(1)相对应。
(3) PKCS1Padding
PKCS1Padding是RSA公司的公钥密码学标准――PKCS #1 (v1.5)[6]文档中定义的填充方式,它是RSA算法实现加解密操作时常使用的一种填充。
PKCS #1(v1.5)文档中描述了PKCS1Padding的实现过程。加密块是一个8位字节串EB,它由块标记BT,填充块PS和数据D组成,即EB = 00 || BT || PS || 00 || D。其中,块标记BT是一个标记字节,表示加密块的结构。BT有三个取值00,01,或02值,其中私钥操作为00或01,公钥操作为02。|| PS ||为填充的数据,对于00型,填充串为0x00;对于01型,填充串为0xFF;对于02型,填充串为假散列生成的非0值。 PKCS #1(v1.5)中规定当RSA的密钥长度是1 024 b,如果使用PKCS1Padding填充,则原文数据长度必须小于117 B,即至少有8 B需要填充。
如果原文不满足长度要求,则在加密前需要进行填充。假定原文数据长度为96 B,则填充处理后字符串分别如下:
原文数据:
61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
71 72 73 74 75 76 77 78 79 7A 30 31 32 33 34 35
61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
71 72 73 74 75 76 77 78 79 7A 30 31 32 33 34 35
61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
71 72 73 74 75 76 77 78 79 7A 30 31 32 33 34 35
私钥操作,00型,填充后数据:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
……
私钥操作,01型,填充后数据:
00 01 FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00
61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
……
公钥操作,02型,填充后数据:
00 02 58 DE B9 E7 15 46 16 D9 74 9D EC BE C0 EA
B5 EC BB B5 0D C4 29 95 6C 18 17 BE 41 57 19 00
61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
……
从填充后的数据可以看出,对于00型的私钥操作,要求原文数据必须不能包含0x00,或者知晓数据长度,否则将不能准确移去填充数据。因此在加解密操作中,常使用01型的私钥操作和02型的公钥操作。
(4) OAEPWithAndPadding
OAEPWithAndPadding是RSA公司的公钥密码学标准――PKCS #1(v2.1)[7]文档中定义的填充方式,其中为数字摘要算法,为掩模生成函数。该填充方式也是RSA算法实现加解密操作时可以使用的一种填充,相对于PKCS1Padding,它生成的原文数据进行加密比较安全,但加密速度比较慢。
PKCS #1(v2.1)文档中描述了OAEPWithAndPadding的实现过程。生成加密块的过程可以分为以下三步[8]:
①M1=Mask(H(P))‖PS‖01‖M),S),
②M2=Mask(S,M1),
③MP=00‖M2‖M1。
其中:M为原文数据;P为给定字符串(默认情况时为空字符串);函数H()为哈希运算;函数Mask()为掩模生成函数;PKCS #1(v2.1)文档中定义该函数为MGF1;S为随机种子;PS为填充字符串,每个字节0x00;MP为最终生成的加密块。
如果使用OAEPWithAndPadding,则原文数据的最大长度为Maxlen=Klen-zhlen-2 ,其中Klen表示密钥的长度,hlen表示摘要运算后数据的长度。假如密钥长度为128 B,为SHA1,则原文数据最大为86 B。该填充方式只能用在公钥加密、私钥解密的操作中。假定原文长度16 B,使用OAEPWithSHA1AndMGF1Padding填充处理后字符串如下:
原文数据:
61 62 63 64 65 66 30 31 32 33 34 35 36 37 38 39
填充后数据:
00 31 1E B5 65 F2 C2 BF D1 F9 49 AD 46 EE A3 80
DA 67 30 B8 17 99 9D 42 3F E8 7F EB 44 5A FF CD
82 B1 C7 D0 75 4D C7 3B 0C A0 B6 49 A4 F9 E8 D3
21 6F 68 D4 A6 EE 1A 34 DE A9 A2 90 84 B7 20 C8
68 B9 7B 36 E1 7F 83 5E B8 D2 1B 56 8C 24 01 9C
ED 33 4A C7 11 2E E4 65 83 D7 10 46 F7 27 7E E4
5C 9F 69 9D 86 8B FC 72 EB FA 70 A4 3C 88 76 AF
EC B6 D7 89 E3 98 F4 0E 68 24 EF 48 AE 37 85 5C
深入分析和理解SunJCE Provider支持的加密类Cipher参数中的填充方式,就能够在Java环境下选择和确定加解密时传入的参数。Java环境下,常用对称加密算法常使用ECB或CBC模式、PKCS5Padding(或PKCS7Padding)填充方式;对于非对称加密算法RSA,则经常使用ECB或NONE无模式、PKCS1Padding填充方式。对Java环境下使用RSA公钥实现加密,C环境下使用RSA私钥实现解密进行了测试。测试中,约定了加密模式为 ECB、填充方式为PKCS #1中定义的方式。 原始明文数据:
30 31 32 33 34 35 36 37 38 39 61 62 63 64 65
填充后的数据:
00 02 57 5B 7A 5F 93 B8 96 09 B7 5E 4D B0 4D 1E
D2 C7 2E 04 1C 60 A6 CF D2 E3 25 C9 ED 47 60 77
75 E3 47 82 6E 46 ED 76 2A B8 A0 B4 14 B7 0F 37
48 96 45 26 E0 67 51 58 45 27 1E 9F B4 2F 96 79
E9 89 E9 DE 29 72 B5 A8 C3 71 54 0D 75 53 59 9E
43 30 04 20 2C 4D B5 2A D4 45 7A FA FC 48 2F 52
1E 62 A0 1E A8 4A 5D 0B 34 52 D2 6F FF AA C4 E2
00 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65
加密后的数据:
71 89 28 DC 9C 62 50 B1 9D 21 BC 26 AB A6 50 1B
80 7E BC FE CC A6 5E 9F BC 9A 8A 2E 69 B2 90 EE
8F F9 A0 F9 32 C2 C8 B7 D5 01 8D 73 3C 0C FA B5
FE 6E 2A 4F 19 0C 62 42 E4 66 45 8A DD CA AE 55
12 35 E0 6C F3 0F FC B4 95 BB B0 44 09 09 F9 5A
D9 DD F4 B2 B5 63 D6 C6 4F 8D 67 62 6D 69 7B 31
C2 17 A4 04 F8 67 A3 3F C4 6E 4D 94 8A 38 E5 BA
63 94 BB 17 41 15 27 48 33 34 90 79 1B 3A FD E4
解密后的数据:
00 02 57 5B 7A 5F 93 B8 96 09 B7 5E 4D B0 4D 1E
D2 C7 2E 04 1C 60 A6 CF D2 E3 25 C9 ED 47 60 77
75 E3 47 82 6E 46 ED 76 2A B8 A0 B4 14 B7 0F 37
48 96 45 26 E0 67 51 58 45 27 1E 9F B4 2F 96 79
E9 89 E9 DE 29 72 B5 A8 C3 71 54 0D 75 53 59 9E
43 30 04 20 2C 4D B5 2A D4 45 7A FA FC 48 2F 52
1E 62 A0 1E A8 4A 5D 0B 34 52 D2 6F FF AA C4 E2
00 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65
去填充后的数据:
30 31 32 33 34 35 36 37 38 39 61 62 63 64 65
从测试数据可以看到,Java环境下的服务端使用公钥加密后,通过网络将密文传输到C环境下的客户端,客户端使用私钥和指定加密模式对数据进行解密,再利用PKCS1Padding的填充原理将填充部分移去,即可获得正确的原文。
3 结 语
本文围绕着Java编程环境下SunJCE提供的加密类――Cipher,对加密模式和填充方式展开了分析,并运用实例对填充方式进行了解释。在不同语言环境下的通信双方,根据传输信息的重要程度来协商加密的模式和填充方式。双方不但能够在通信中保护重要敏感的信息,还能够利用模式与填充方式的原理,在接收信息时成功实现解密。
参考文献
[1] Sun Microsystems. Java cryptography architecture Sun providers documentation for Java platform standard [M]. 6 ed. USA: Sun Microsystems, 2011.
[2] MEYERS R K, FRANK C E. Implementing your own cryptographic provider using the Java cryptography extension [R]. [S.l.]: [s.n.], 2011.
[3] Anon. Using padding in encryption [EB/OL]. [2013?01?28]. http://www.di?mgt.com.au/cryptopad.html.
[4] W3C. XML encryption syntax and processing [EB/OL]. [2002?12?10]. http://www.w3.org/TR/2002/REC?xmlenc?core.