電子署名とは
Wikipediaには
電子署名とは、電磁的記録に付与する、電子的な徴証であり、
紙文書における印章やサインに相当する役割をはたすものである。
主に本人確認や、改竄検出符号と組み合わせて偽造・改竄の防止のために用いられる。
電子署名を実現する仕組みとしては、公開鍵暗号方式に基づくデジタル署名が有力である。
とあります。
自分の秘密鍵でファイルに署名し、それを予め配布しておいた公開鍵で検証することで、送信者が「正しい人」であることがわかります。
Javaで書いてみました
Tinkは、バージョンアップのたびに、APIが変わり、以前書いたコードが非推奨となることが多いため、その都度ドキュメントを見ながら修正しています。
以下に示すコードはtink-1.12.0.jarを用いています。依存ライブラリーとして protobuf-java と gson が必要です。
package sample2024;
import com.google.crypto.tink.CleartextKeysetHandle;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.JsonKeysetReader;
import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.TinkJsonProtoKeysetFormat;
import com.google.crypto.tink.signature.SignatureConfig;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.Base64;
public class SignatureTest {
public static void main(String[] args) {
try {
String plainText = "こんにちは"; // 署名したいテキスト
System.out.println("署名したいテキスト:" + plainText);
SignatureConfig.register();
System.out.println("電子署名秘密鍵を生成");
KeysetHandle privateKeysetHandle
= KeysetHandle.generateNew(KeyTemplates.get("ECDSA_P256"));
// 秘密鍵をファイルに保存する場合(セキュリティー上推奨されていません)
// String SignaturePrivKey = "signature_priv.key";
// Path sigPrivFile = Paths.get(SignaturePrivKey);
// System.out.println("Hybrid秘密鍵を保存");
// String serializedmacKeyset = TinkJsonProtoKeysetFormat.serializeKeyset(
// privateKeysetHandle, InsecureSecretKeyAccess.get());
// Files.write(sigPrivFile, serializedmacKeyset.getBytes(UTF_8));
// 秘密鍵をファイルから読み込む(セキュリティー上推奨されていません)
// serializedmacKeyset = Files.readString(sigPrivFile, UTF_8);
// 読み取ったテキストから鍵を抽出する
//KeysetHandle keysetHandle2 = CleartextKeysetHandle.read(
// JsonKeysetReader.withString(serializedmacKeyset));
// 秘密鍵から公開鍵を作成
KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();
System.out.println("電子署名公開鍵(相手に渡すもの):" + toJson(publicKeysetHandle));
// 電子署名をするためには秘密鍵と もとのテキストが必要
PublicKeySign signer = privateKeysetHandle.getPrimitive(PublicKeySign.class);
byte[] signature = signer.sign(plainText.getBytes());
String sign_data = new String(Base64.getEncoder().encode(signature));
System.out.println("電子署名:" + sign_data);
PublicKeyVerify verifier = publicKeysetHandle.getPrimitive(PublicKeyVerify.class);
// 署名を検証するためには電子署名と もとのテキストが必要
verifier.verify(signature, plainText.getBytes());
System.out.println("電子署名が検証されました");
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
private static String toJson(KeysetHandle key) throws GeneralSecurityException {
return TinkJsonProtoKeysetFormat.serializeKeyset(key, InsecureSecretKeyAccess.get());
}
}
実行結果
署名したいテキスト:こんにちは
電子署名秘密鍵を生成
電子署名公開鍵(相手に渡すもの):{"primaryKeyId":3084469744,"key":[{"keyData":{"typeUrl":"type.googleapis.com/google.crypto.tink.EcdsaPublicKey","value":"EgYIAxACGAIaIQDS8szXsh4hV1Rxp5XFfA5CP3wbPvGgChsIsPTEkfkpxCIhAK5aeSDBZNKvHH4PYZNIuee5gykLtDk6AQQPgvKWrBzt","keyMaterialType":"ASYMMETRIC_PUBLIC"},"status":"ENABLED","keyId":3084469744,"outputPrefixType":"TINK"}]}
電子署名:AbfZRfAwRgIhAJcqUHB/JlzDrPsJyFkqizlLCCnbG8CqkdX7ECUb9YWaAiEA11bfaG1Dn9Uvw0gV3ILZhZ3zIKYMyYPwhOo6UfZ6YBU=
電子署名が検証されました