非対称暗号化の例

では、暗号化における公開鍵ペアの使用について説明しました。公開鍵インフラストラクチャのもう1つの重要な用途は、デジタル署名です。デジタル署名は、1つの重要な違いを持つ手書き署名のデジタル同等物です。彼らは一意ではなく、メッセージの産物として来ます。

A valid digital signature gives a recipient reason to believe that the
message was created by a known sender (

authentication

), that the
sender cannot deny having sent the message (

non-repudiation

), and that
the message was not altered in transit (

integrity

). (Source:

Wikipedia

)

1.公開鍵と秘密鍵のペアを生成する

公開鍵と秘密鍵のペアを生成するコードは、

Asymmetric Cryptographyの例

で使用されているものと同じですが、手順1を参照するか、すべてのソースを含む記事 –

GenerateKeys.java


java-digital-signatures-1

2.メッセージに署名する

次にメッセージを書いて署名しなければなりません。メッセージとシグネチャは別々のファイルにすることができますが、この例では、それらを

byte[]`の `List`に追加し、

Object`としてファイルに書き込みます。

Message.java

package com.techfou.sender;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;

public class Message {
    private List<byte[]> list;

   //The constructor of Message class builds the list that will be written to the file.
   //The list consists of the message and the signature.
    public Message(String data, String keyFile) throws InvalidKeyException, Exception {
        list = new ArrayList<byte[]>();
        list.add(data.getBytes());
        list.add(sign(data, keyFile));
    }

   //The method that signs the data using the private key that is stored in keyFile path
    public byte[]sign(String data, String keyFile) throws InvalidKeyException, Exception{
        Signature rsa = Signature.getInstance("SHA1withRSA");
        rsa.initSign(getPrivate(keyFile));
        rsa.update(data.getBytes());
        return rsa.sign();
    }

   //Method to retrieve the Private Key from a file
    public PrivateKey getPrivate(String filename) throws Exception {
        byte[]keyBytes = Files.readAllBytes(new File(filename).toPath());
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePrivate(spec);
    }

   //Method to write the List of byte[]to a file
    private void writeToFile(String filename) throws FileNotFoundException, IOException {
        File f = new File(filename);
        f.getParentFile().mkdirs();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
        out.writeObject(list);
        out.close();
        System.out.println("Your file is ready.");
    }

    public static void main(String[]args) throws InvalidKeyException, IOException, Exception{
        String data = JOptionPane.showInputDialog("Type your message here");

        new Message(data, "MyKeys/privateKey").writeToFile("MyData/SignedData.txt");
    }
}

出力:


java-digital-signatures-2

Your file is ready.


java-digital-signatures-3

3.署名を確認する

受信者はファイル

(彼はそれが2バイト配列の `リスト`であることを知っています;メッセージと署名)

があり、そのメッセージが事前共有された公開鍵で期待されるソースから来たものであることを検証したい。

VerifyMessage.java

package com.techfou.receiver;

import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.List;

public class VerifyMessage {
    private List<byte[]> list;

    @SuppressWarnings("unchecked")
   //The constructor of VerifyMessage class retrieves the byte arrays from the File
   //and prints the message only if the signature is verified.
    public VerifyMessage(String filename, String keyFile) throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
        this.list = (List<byte[]>) in.readObject();
        in.close();

        System.out.println(verifySignature(list.get(0), list.get(1), keyFile) ? "VERIFIED MESSAGE" +
          "\n----------------\n" + new String(list.get(0)) : "Could not verify the signature.");
    }

   //Method for signature verification that initializes with the Public Key,
   //updates the data to be verified and then verifies them using the signature
    private boolean verifySignature(byte[]data, byte[]signature, String keyFile) throws Exception {
        Signature sig = Signature.getInstance("SHA1withRSA");
        sig.initVerify(getPublic(keyFile));
        sig.update(data);

        return sig.verify(signature);
    }

   //Method to retrieve the Public Key from a file
    public PublicKey getPublic(String filename) throws Exception {
        byte[]keyBytes = Files.readAllBytes(new File(filename).toPath());
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(spec);
    }

    public static void main(String[]args) throws Exception{
        new VerifyMessage("MyData/SignedData.txt", "MyKeys/publicKey");
    }
}

出力:

VERIFIED MESSAGE
----------------

こんにちはmkyong.comから!

Download Source Code

Download –

digitalsignatures.zip

(6 KB)