15.2.3 利用SATSA高级API进行加解密
除了SATSA定义的两个可选包可用于连接加密硬件外,还有两个包能够实现如今的许多移动应用程序所需的常见加密操作。SATSA-CRYPTO包 包含java.security包、java.security.spec包、javax.crypto包以及javax.crypto.spec包的一 个子集,提供了用于公私钥管理、消息摘要、签名验证以及数字加密的API。SATSA-PKI安全包包含javax.microedition.pki和 javax.microedition. securityservice,定义了支持基本用户证书管理的类。
使用SATSA-CRYPTO API,让我们看一下两个常见操作,在应用程序开发期间可能会用到它们。这两个操作是:创建消息摘要和加密(或解密)消息。
1. 使用SATSA-CRYPTO API创建消息摘要
移动应用程序可能需要执行的最常见的密码操作就是创建消息摘要。如今,许多Web服务API使用消息摘要作为一种阻止篡改Web服务请求或响应的有 效负荷(payload)的方式;消息摘要可以是HTTP的头部或Web服务的参数,也可以简单地附加到Web服务头部之后。这就像使用SATSA- CRYPTO API一样简单,如代码清单15-3所示。
代码清单15-3 创建消息摘要
SATSA-CRYPTO API提供了MessageDigest类,该类提供了一个用于创建消息摘要算法实现的静态工厂,以及一个该消息摘要算法的一个接口。通过调用 MessageDigest的getInstance函数并传入想要其实现的摘要函数("MD5"或"SHA-1")的名称,可以获得 MessageDigest的一个具体实例。生成的MessageDigest对象调用其update方法来使用你传给它的字节数组,当调用该对象的 digest方法时,它将提供生成的消息摘要并重置算法。
这段代码假设你拥有一个Web请求,并且想在webRequest中为该请求生成一个MD5摘要。由于MessageDigest接口处理字节数 组,所以这段代码首先获取Web请求的字节数组表现形式,然后声明变量来包含生成的摘要。完成之后,将生成MD5 MessageDigest实现的一个实例,并调用md.update,将组成webRequest的字节传递给它。对于较长的文档,可以多次调用 md.update。当使用update将消息提供给MessageDigest实例之后,代码将要求该实例使用digest方法计算摘要,这会使用一个 字节数组来存储输出和数组中的字节数。
SATSA-CRYPTO提供的MessageDigest实现通常包括MD5和SHA-1算法,但是无法保证每种算法都可用。因此,应用程序应该准备好处理NoSuchAlgorithmExecption。
也可以使用SATSA-CRYPTO API来验证消息摘要,创建源文档的一个消息摘要并将其与提供的消息摘要进行比较。没有用于比较消息摘要的API;可以对每个摘要中的字节进行循环,并逐字节进行比较,以确定每个消息摘要是否相等。
2. 使用SATSA-CRYPTO API加密和解密
在大多数环境下,只有在将数据从设备发送出并在网络上传输时才对其进行加密。在这种情况下,HTTPS通常就能满足数据安全需求了;有时还需要以一 种加密格式在将数据存储在本地,或者使用除HTTPS之外的协议交换数据。SATSA-CRYPTO API提供了用于加密和解密数据的接口,但带有一个局限性:尽管可以,采用公钥(也称为对称)密码算法加密使用SATSA-CRYPTO API的数据,但是无法解密使用公钥密码算法加密的数据。
最好将密码的SATSA-CRYPTO API想作一个接口,而不是一个具体实现。对于给定的目标,无法确切地知道将会遇到哪种密码实现;一种设备可能支持DES(Data Encryption Standard,数据加密标准)、RC4(Rivest Cipher 4)以及AES(Advanced Encryption Standard,高级加密标准),而另一种设备可能仅支持DES。无论支持哪种实现,使用SATSA-CRYPTO密码接口的一般方法都是一样的。
(1) 以字节数组的形式生成想要加密的明文。
(2) 同样以字节数组的形式生成要用于加密明文的密钥。
(3) 生成期望的密码实现的一个实例,这将是java.security.Cipher的一个实例。
(4) 初始化密码。
(5) 使用Cipher's update方法逐步加密明文,或者使用Cipher's doFinal方法通过一步操作执行加密。
你可能已经预料到,解密是加密的逆过程;指定密码实现并指明应该在解密模式下使用它,而无须像步骤3中那样指定一个密码实现。传递加密的文本,而不是传递步骤5中的明文。考虑代码清单15-4,其中演示了加密消息的过程。
代码清单15-4 加密消息
这段代码按照上面列出的每步算法编写;尤其注意,当初始化Cipher实例时,使用ENCRYPT_MODE作为选定模式。解密将是加密的逆过程, 解密算法的代码只需将相应参数的DECRYPT_MODE传递给init。运行此代码之后,如果没有异常,字节数组cipherTextBytes将包含 加密的文本。
各种密码算法在处理输入的方式上可能不尽相同;一些算法(比如DES)是块密码,它要求以大小均匀的块的形式提供输入,比如64字节的块。当使用块 密码时,必须将输入填充为与块的边界一致;更复杂的是,一些块密码还是非对称的,也就是说输入块的大小与输出块的大小不同。其他密码算法(比如RC4)都 是流密码:它们获取一个字节流(明文或加密的文本),然后进行加密或解密。当使用块密码时,一定要确保将所有块都传递给了update和doFinal方 法。
当使用Cipher接口加密或解密时,可能会发生一些事情;针对各种事情,API会分别抛出以下异常。
当输入未被正确填充或块的大小错误时,API为块密码抛出BadPaddingException或Illegal- BlockSizeException。
当密码算法使用了一个无效的密钥时,API抛出InvalidKeyException。
当你尝试在初始化消息之前,使用密码算法对其加密或解密时,API抛出Illegal- StateException。
如果你试图获取一个不受支持的算法的Cipher实例,API将抛出NoSuchAlgorithmException。
注意 在真实世界中,你不应该随便将密码算法的私钥嵌入到源代码或其他易于读取的资源中,比如JAR文件的组成部分。恶意用户可能通过反编译应用程序或JAR找 到密钥。相反,应该在分发时创建密钥,每个应用程序使用不同的密钥,并且仅适用安全的HTTP分发应用程序JAD。但是,这将意味着应用程序不能由 Java Verified Program的参与者进行签名和验证。也可以提供一个Web服务来安全地生成密钥,并通过HTTPS传递给你的应用程序。
原文地址:http://book.51cto.com/art/200908/145122.htm[转载]