Java Digital Signature2025年5月8日 | 阅读14分钟 数字签名是一种验证数字消息和文档的权威性的机制。它因提供比其他签名更高的安全性而备受欢迎。在Java中,JDK安全API用于创建和实现数字签名。在本节中,我们将讨论数字签名机制,并**在Java程序中实现数字签名机制**。 ![]() 数字签名数字签名是一种用于签署文档、邮件、消息等的电子签名。它验证消息或文档的真实性和完整性。它与手写签名、印章或戳记相同。它广泛用于验证数字消息、财务文件、身份证件等。 简而言之,我们可以说它确保了以下几点:
数字签名由目录服务器使用,该服务器维护信息的完整性。当我们对要传输的信息应用加密和消息摘要时,信息的接收者可以轻松确定信息在传输过程中没有被篡改。 用于篡改检测和身份验证的功能称为单向哈希。它也称为消息摘要。 单向哈希只不过是一个固定长度的长数字。它具有以下特征:
因此,公钥和私钥是数字签名数据的关键部分。签名应用程序不加密实际信息或数据,而是生成信息或数据的单向哈希。之后,它使用私钥加密哈希。加密的哈希以及其他信息(如哈希算法)被称为数字签名。下图描绘了这一点。 ![]() 术语数字签名中使用了以下三个主要的专业术语。 公钥基础设施(PKI):这是一组(硬件、软件和其他资源)模块,用于安全地管理数字签名。它包括一对密钥,即公钥和私钥。 公钥由所有需要验证签名的人共享。而私钥根本不共享。它仅由签名者用于数字签名消息或文档。 证书颁发机构:这些是受信任的组织,它们在确保密钥安全和数字证书方面得到广泛认可。 数字证书:数字证书包含公钥,并指明与该密钥关联的身份。通常,证书由受信任的机构颁发,有效期为一段时间。 数字签名优势
数字签名用途数字签名用于以下领域:
数字签名工作原理数字签名基于非对称加密。它也称为公钥加密。有许多公钥算法。但其中,最常用的是RSA(Rivest-Shamir-Adleman)和SHA(Secure Hash Algorithms)。这两种算法都用于安全的数据传输。这些算法会生成一个数学上链接的密钥对,一个是公钥,另一个是私钥。 创建数字签名的个人使用私钥来加密与签名相关的数据。接收数字签名数据的人使用签名者的公钥,这是解密数据的唯一方法。 最后,比较两个加密哈希值,以检查其真实性。如果匹配,则文档有效。 如果接收者无法使用签名者的公钥打开文档或消息,则表示文档或签名存在问题。 数字签名机制要求所有各方相信创建签名的人会保密私钥。如果其他人访问了私钥,那么该方就可以以私钥持有者的名义创建欺诈性的数字签名。 ![]() 发送带数字签名的消息从技术上讲,数字签名是消息或文档的加密哈希。这意味着数字签名会从消息生成哈希。之后,生成的哈希会使用私钥进行加密。我们可以为此使用SHA和RSA哈希算法。 当我们发送消息时,加密的哈希和相应的密钥也会与消息一起发送,这被归类为带有数字签名的消息。 接收带数字签名的消息当接收者收到带有数字签名的消息时,接收者会从消息中生成一个新的哈希。之后,它使用公钥解密接收到的哈希。最后,它比较两个哈希。如果它们相等,则数字签名已验证。 这里需要注意的是,我们只加密了消息哈希,而不是整个消息。因为数字签名仅确保消息在传输过程中未被篡改。下图演示了这一点。 ![]() 数字签名流程假设X(发送者)向Y(接收者)发送一条消息。X 计算消息的哈希值,并附加一个他想用私钥与消息一起发送的签名。 在接收者(Y)端,消息再次生成哈希,并使用 X 的公钥解密签名。之后,比较哈希值。如果在接收者(Y)端哈希值匹配,则签名已验证并确认文档有效。同时,也确保了消息在此期间未被篡改。 注意:在继续本节之前,请确保您已充分了解哈希算法。在Java中实现数字签名生成数字签名Java 提供了JDK 安全 API,允许我们处理数字签名。要生成数字签名,我们必须遵循以下步骤:
让我们按照步骤进行。 数字签名 Java 程序创建初始程序结构GenerateDigitalSignature.java 生成公钥和私钥创建密钥对生成器 如上所述,数字签名需要私钥。此外,还需要相应的公钥来验证签名。但有时密钥对已存在于文件中。如果不存在,我们需要生成它。 我们可以使用 KeyPairGenerator 类来生成密钥对。它生成 1024 位长度的密钥。 我们调用 KeyPairGenerator 类的 getInstance() 方法。getInstance() 方法有两种形式。两者都有两个参数,第一个参数是算法,第二个参数是提供程序(String 类型)。 其中DSA(数字签名算法)是要使用的算法,SUN是 JDK 内置的默认提供程序。 现在,我们将初始化密钥对生成器。 初始化密钥对生成器 所有密钥对生成器都提供了密钥大小和随机性的概念。KeyPairGenerator 类的 initialize() 方法接受这两个参数。 对于 DSA,密钥大小为 1024。所以,我们将密钥大小设置为1024。另一个参数随机性必须是 SecureRandom 类的实例。它提供了一个加密强随机数生成器(RNG)。它使用内置 SUN 提供程序提供的 SHA1PRNG 算法。 Java 8 提供了一系列已知的强SecureRandom。它属于 java.security.Security 类的 securerandom.strongAlgorithms 属性。因此,我们也可以使用 SecureRandom.getInstanceStrong() 方法,因为它获取已知强算法的实例。 最后,生成一对密钥。 生成密钥对 使用 KeyPair 类,我们生成公钥和私钥。 下一步是签名数据。 签名数据 Java 提供了 Signature 类,可用于创建数字签名。 获取签名对象 在上面的语法中,需要注意的是,我们提到了签名算法名称以及签名算法使用的消息摘要算法,即SHA1withDSA。其中SHA-1是消息摘要算法,DSA是签名算法。组合起来,这是一种使用 SHA-1 消息摘要算法来指定 DSA 算法的方法。 注意:在指定签名算法名称时,还应包含签名算法使用的消息摘要算法的名称。SHA1withDSA 是指定 DSA 签名算法的一种方式,使用了 SHA-1 消息摘要算法。初始化签名对象 签名对象在使用前必须初始化。用于签名的初始化方法需要一个私钥。因此,我们将使用上面创建的PrivateKey对象的(priv)。 向签名对象提供要签名的数据 它使用要签名的数据。为了提供数据,我们使用 Signature 类提供的 update() 方法。 生成签名 当我们向 Signature 对象提供了所有数据后,它允许我们为此数据生成数字签名。 在下一步,我们将保存签名。 将签名和公钥保存在文件中在上一步中,我们生成了签名字节。在此步骤中,我们将签名和公钥都保存在两个单独的文件中,以便可以与他人共享。 保存签名 我们将使用以下代码将签名保存在名为sig的文件中。 保存公钥 在这里,我们将保存编码的公钥。我们通过使用 getEncoded() 方法来获取编码的密钥。它返回编码后的字节。我们将相同的字节存储在文件中。 编译并运行程序完成以上所有步骤后,我们得到以下源代码。 GenerateDigitalSignature.java 请记住:不要忘记指定要签名的文件名。我们使用了文件 输出 ![]() 当我们执行程序时,它会在指定位置生成两个名为 publickey.txt 和 signature.txt 的文件。 ![]() 让我们看看文件里面的内容。 digital.txt ![]() publickey.txt ![]() signature.txt ![]() 我们看到两个文件都包含人类无法读取的加密数据。 验证数字签名现在我们将验证上面生成的签名。为了验证签名,请遵循以下步骤:
让我们按照步骤进行。 准备初始程序结构创建一个程序,其中我们将实现验证签名的逻辑。我们创建了一个名为 VerifyDigitalSignature 的 Java 文件。 VerifyDigitalSignature.java 在上面的代码片段中,我们导入了一个名为 java.security.spec 的包,该包提供了 X509EncodedKeySpec 类。 输入和转换编码的公钥字节在此步骤中,我们将导入编码的公钥字节并将其转换为公钥。因此,为了读取公钥,请使用以下代码片段。 上面的代码将字节数组转换为编码的公钥字节。现在,从其编码实例化一个 DSA 公钥。为此,我们可以使用 KeyFactory 类。它提供了不透明密钥(密钥类型)和密钥规范之间的转换。 不透明密钥使用 X509 标准,该标准用于确定算法名称、格式名称和编码的密钥字节。请注意,它不提供密钥材料。 为此,我们需要一个密钥规范,可以通过使用以下代码来实现。假设密钥是根据 X509 标准编码的。 现在,我们将使用 KeyFactory 类的对象来转换密钥。请注意,该对象必须能够处理DSA密钥。 最后,从 KeyFactory 类的对象生成公钥规范。 输入签名字节从指定的文件中,将签名字节作为 CLI 输入。 验证数字签名为验证初始化签名对象 要验证签名,我们需要 Signature 类的一个对象。它使用与生成签名时相同的签名算法。 初始化 Signature 类对象。用于验证的初始化方法需要一个公钥对象(pubkey)作为参数。 向签名对象提供要验证的数据 为签名对象提供签名已生成的所有的相关数据。 验证签名 我们已经向 Signature 对象提供了所有相关数据。现在,我们可以验证数字签名了。 完成所有步骤后,我们得到以下源代码。 VerifyDigitalSignature.java 现在,编译并运行程序。 编译并运行程序在运行上述程序时,在控制台中指定三个参数:
运行程序后,我们得到以下输出。 输出 ![]() 我们看到签名已验证。 让我们对生成数字签名的文件进行一些修改。我们从 digital.txt 文件中删除了最后一个单词。删除单词before后,文件如下所示。 digital.txt ![]() 现在,仅运行 VerifyDigitalSignature.java 文件,看看会发生什么。 ![]() 从上面的输出中,我们可以观察到,每次我们更改或修改数据时,密钥都会改变,并且签名验证会返回false。 在上面的程序中,我们使用 SHA-1 和 RSA 算法来生成和验证数字签名。类似地,我们也可以使用其他非对称算法来生成和验证数字签名。 使用 RSA 和 SHA256 算法生成和验证数字签名让我们创建另一个 Java 程序,但在这个程序中,我们将使用SHA256算法和RSA。其余的代码和概念相同。 DigitalSignature.java 输出 Signature Value: 0B5F7239F701F38932006DA86ED1DB0CA7883F9AE5D1934D6DC1ACB474B60CB69B39D7A983778AD6979967E0C1A9C73E5DD39CF3991B9612EABE25DAF84ECFCD52C7EBE9FD27DFE0BFF426E27476D35A30C87A94B0EA2CA99812DE4A6DA10614533A05CBF37833560E898B88C4733DF4A22C2B89DE56848A59DDE7CC0BBED0F0CE086DC6CC2789511C17008CB2BA8F2B30D6394221C2414C065385E270ADC191716BAE4B34B2790355D67D4B30AA514438515B5ACDA5E4FB846BD42226DE045294DE949AA15DE8CBD6885E29B9059136DB36347AEC5833D9B60EBEA72484A5F3B79B12E4AF6A0B9D8EB0EFBDBEC892E094E1418C6249C368F4ED39FD6EFEAE9A Verification: true |
在 Java 中,JSON 在存储数据方面发挥着重要作用。ArrayList 是一种特殊的 Array,其大小是动态的。它还可以随时用于存储或删除数据。ArrayList 使用 List 的所有方法,并维护插入顺序,因为它实现了...
阅读 3 分钟
在本节中,我们将讨论什么是霓虹数,并创建一个 Java 程序来检查给定数字是否为霓虹数。我们还将找出指定范围内的所有霓虹数。霓虹数:一个正整数,其数字之和...
阅读 3 分钟
?使用 Java 编程不依赖于任何特定平台。这意味着带有 Java 解释器的系统可以执行 Java。这就是 Java平台独立性的原因。Java 解释器将 Java 字节码(.class 文件)转换为操作系统可以理解的代码。我们将...
阅读 3 分钟
问题陈述 编写一个 Java 程序,确定网格数字序列是否构成等比数列(GP)。等比数列定义为:除了第一个数之外,每个后续数都是通过将前一个数乘以一个常数得到的。程序应:...
阅读 6 分钟
二次方程在数学以及物理工程和经济学等领域的普遍应用中非常重要。二次方程通常表示为标准形式:ax^2+bx+c=0,其中 a、b 和 c 是常数,而...
阅读 4 分钟
词典顺序这个术语是一个数学术语,也称为:词典顺序、字典序、字母顺序或字典顺序。本节将涵盖词典顺序的主题、其定义以及其他详细信息。之后,我们将学习如何使用词典顺序的概念...
7 分钟阅读
模式被认为是编程中更受欢迎的主题之一,其中主要目标之一是测试构建逻辑的能力。循环最常用于实现它们,尽管本文描述了一种在没有循环的情况下打印所需模式的方法,并且...
阅读 4 分钟
Java 的多线程功能是一种有效的工具,可以通过允许多个线程同时运行来提高程序性能和资源利用率。线程层级的概念为管理并发工作提供了有组织的方法,是 Java 线程模型的基础。本节...
5 分钟阅读
哈希表是计算机科学中的一种基本数据结构,可提供高效的键值对存储和检索。它们在搜索、插入和删除操作方面实现了平均恒定的时间复杂度,这使其对于各种应用(如数据库索引、缓存和关联数组)极具价值。
阅读 6 分钟
Java 提供了强大的面向对象编程功能,称为类。类可以作为蓝图来创建对象,因为它既包含数据又包含行为。除了定义共享的抽象类之外,还可以直接实例化的具体类...
阅读 4 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India