XMLのデジタル署名をJavaで実装する
こんにちは。株式会社レスキューナウで基幹システムを担当しているエンジニアです。
今回はXMLのデジタル署名をJavaで実装した時のお話です。
デジタル署名とは、データの改ざんや作成者のなりすまし等を防ぐ為に付けられる、暗号化された電子的な署名です。
XMLデジタル署名の仕様は、W3C(World Wide Web Consortium)とIETF(Internet Engineering Task Force) により標準化されています。
XML署名の種類
XMLのデジタル署名には次の種類があります。
今回はEnveloped署名を使用します。それでは実際に作成していきます。
デジタル署名用の鍵生成
まずは、デジタル署名で使用する公開鍵と秘密鍵を生成します。
# openssl req -out testSignature.crt -nodes -keyout testSignature.pem -newkey rsa:4096 -sha256 -x509 -days 365
Javaで使用するために、PEM形式の秘密鍵をPKCS #8・DER形式に変換します。
# openssl pkcs8 -in testSignature.pem -outform DER -out testSignature.pk8 -topk8 -nocrypt
JavaでXMLデジタル署名APIを使用する
生成された鍵ファイルを使用して、JavaでXMLのデジタル署名を作成します。
JavaのXMLデジタル署名APIは、java.xml.cryptoモジュールのパッケージを使用します。
こちらがデジタル署名APIを使用して、デジタル署名を付加するプログラム例です。XML Documentにデジタル署名を付加して、ファイルに出力しています。
/**
* XML Documentにデジタル署名を付加してファイルに出力する
*
* @param document デジタル署名を付加するXML Document
* @param xmlFileName デジタル署名を付加したXMLファイル名
*/
public void createXmlSignature(Document document, String xmlFileName) {
try {
// XMLSignatureFactoryの生成
XMLSignatureFactory xmlsf = XMLSignatureFactory.getInstance("DOM");
DigestMethod dm = xmlsf.newDigestMethod(DigestMethod.SHA256, null);
List<Transform> tf = Collections.singletonList(xmlsf.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null));
Reference rf = xmlsf.newReference("", dm, tf, null, null);
CanonicalizationMethod cm = xmlsf.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null);
SignatureMethod sm = xmlsf.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null);
SignedInfo si = xmlsf.newSignedInfo(cm, sm, Collections.singletonList(rf));
// 秘密鍵の読込
FileInputStream fis = new FileInputStream("testSignature.pk8");
byte[] privateKeyByte = new byte[fis.available()];
fis.read(privateKeyByte);
fis.close();
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(privateKeyByte);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKey privateKey = (RSAPrivateKey) kf.generatePrivate(ks);
// 証明書の読込
KeyInfoFactory kif = xmlsf.getKeyInfoFactory();
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(new FileInputStream("testSignature.crt"));
X509Data x509data = kif.newX509Data(Collections.singletonList(cert));
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(x509data));
DOMSignContext dsc = new DOMSignContext(privateKey, document.getDocumentElement());
// 署名作成
XMLSignature signature = xmlsf.newXMLSignature(si, ki);
signature.sign(dsc);
// 署名付きXMLをファイルに出力
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
FileOutputStream os = new FileOutputStream(new File(xmlFileName));
transformer.transform(new DOMSource(document), new StreamResult(os));
} catch (Exception e) {
e.printStackTrace();
}
}
デジタル署名前のXML文書例
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<data>
<title>XMLデジタル署名テスト</title>
<text>これはXMLデジタル署名のテスト文書です</text>
</data>
デジタル署名後のXML文書例
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<data>
<title>XMLデジタル署名テスト</title>
<text>これはXMLデジタル署名のテスト文書です</text>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>RSl+M5qTbppsqTTTJ449GNjdzXstNIxvqXfcqY0DtuE=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>IiYJHIaUTRV0VV2qVX0EwBWOxCU2cA/qNzThFlpmLwFDbNDXNZ7M4mfECwYsa4LU+TKqc6PmDKDL
oX8CGAhp5SOq9X37KPt/+R2aKSmhK0mSWSBqvCMiOFb3FRpQT7ZH5EpTDX1ksZHwJKlvXvu6g8BL
BgReaS/8+sMJ35ugk9PS06tEK10qZn3lZZze0rGb2BB54yWjzcr1+5YGGqWd+y90QDK/oPdW/iuw
qhZ2g2PE4IaUKYMVl81QOOaLoI8fBrdtekkhwShKvRYBmQCJB1OPlmtT2jjyRFA1FYr3CsDVBCQA
1CF+llZFGzBEj4KJWLD/C8r88tJ/y7F7rvNxLZLS+pNREn1CDHM5nDIeT+1Ovr/qbuy578hS5YnF
0HfMnJVqCmpVddOnlyTmRGboB+vIn7OdFbBT55Ah2/FC150Z9qvkCtG7QyBgXc8neLgdAqY48YGd
cvShdSfNeQc1EqkmBGouyI0/sCHXwBQyqbOSY9yX+4QYw0q8lgboQia60WDDubf0W3cid7iIcfio
4k0KVVzzeeVK8dl33vUn3Rbf5Td+O/+in/nbRv7kzeiIrI6HtmgKGE7bXW4f/ICJX/jv1Z36pQgR
zuV3dv1AcH6Oo8gekW6U8N/F/ncZOoF3ijfFOrrJR0LGgngiyKV8zaT9NzDGdlpdXedXaRLdcFk=
</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIFZTCCA02gAwIBAgIUXQ01s34HLw2Mgv5oYNQtuVuK/6wwDQYJKoZIhvcNAQELBQAwQjELMAkG
A1UEBhMCamExFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55
IEx0ZDAeFw0yMjA2MjAwNDU1MzRaFw0yMzA2MjAwNDU1MzRaMEIxCzAJBgNVBAYTAmphMRUwEwYD
VQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDQQ84DKjiCwGF5MAchYE7x0V8QYttYpfecuRR7b9SWp1Us
AeHx/Emuobl6Kg64c95xiw10l/GiN3mVuxDBXBCE7+0G4XW+f789eqiQmpdC3yqndvfGd2lOFwmd
MPCTukHqIvuVaE1M2GhLX80SrEME6gS22qEI1OrSDqVkx/X9Ttot73IQvGUR0L90wiMfnP1xUm3i
OpJZ5RbW1BmUc8ZzcMYcMqltPN1/nsMsnkJQBMuN6G9t91ibSUf9FaQYLf/E89xoN6ED78wJ3Lgr
Z9S49D217kLhNuNtKVKOD/SO4JO51RQgiXWozPlomA/cy5GyWq4SNij6JgNWsHB7/8qJ6Xkm7CzB
PlOAa6D3qrGNUJaOpOJx6iSXQ4B6ZjcTOKtYq5Br1jml5i12mhg2Uog6SngWxD074Qnt7gvM6nTy
D9miKFsWPKFng6MSaWIsAWJTW36+/vlvHS6ga1VELMru/2mBdLyKqlI60kgAJFxFUkFdNTupKX1T
5unCnT3hAOh+CF4a4PJH3pQ5O90CEWqEAAxc+6DbrsIwP64Cl+SLSBOWL1qQyECdvtcUf36+jc4s
T9fu8YlObKQJ3i2yZQpOiybKnkuJFu+2G0wHtVNeLZnQOK2olvW1+cBEMO166dOHF8B75K2Dh6Q5
bSx/P8DcFlWKlYnvtv/AhOZcp1TnnwIDAQABo1MwUTAdBgNVHQ4EFgQU54FrbI2Z1ImOnA+JGvoP
tAVHtoQwHwYDVR0jBBgwFoAU54FrbI2Z1ImOnA+JGvoPtAVHtoQwDwYDVR0TAQH/BAUwAwEB/zAN
BgkqhkiG9w0BAQsFAAOCAgEACcvy+odp+WQWuzfBsEDvEvkhJgb6HDCDtbFiZrTd5BDXEJvs2FmX
o1Q3GyKdX04JZPiZRRxdn2zgGk3eg/fmHk9n/T9Z08zQEpoNtS8qIiWrDbBzMTwts3zVrXYbqpn+
RJpFrjcGxEAOuuN2y9dF0dTFxW1ETJ9m8535rxpQlHHFJzY0uNIRNi3UL2L2BBgMz1oX7x+r+E7c
pn+jTYzLcZGmSgNfKFSDfU6Klb7Vq8IFXq/yakaGTs2YmOYNql1cTWK0DVVdOX0qj7PIX2GPcufG
Qk7n1Mc0mD50mLgwoiPja/CRYYFD4DEgYr/i2qt7T99Hv3o4IcdIMV9jqVG+z21++b5vwOPblWMd
Eg3+QXq2AAIilEXBeLRFSxyDYFyIC+xaDAlUU3n5FVQhisQzaBIaureeSUE/YDc3S6v/Pu4CkBrO
9Y1ZnpWKSFPaN/TqmScghUa/4QGF73uN4NU0F3dAsvi53BLKw2J/74p/AIxABqV3niqyL/F7Y//p
J6aE+MqKUXlR7KlrJ4myZlmIP2TFKpi+zCzOZRIgXTA54nKjjK44O+I0V7U5nwrBAm7F+zGASQpX
gUAHK613Cj5XYI2cw4kkalsMBFrDXewnqTvmXhcvCqDzcaKu+5tHUoMxQy/koJib64FM/UxcTei2
VBVkYzH6RmJeCGjVAcJ/Qis=
</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</data>
まとめ
これで、デジタル署名付きXMLの完成です。
最後までご覧いただき、ありがとうございました。
最後に
現在、レスキューナウでは、災害情報の提供、災害情報を活用した安否確認サービスなどのWebサービスの開発エンジニアを募集しています!
社員・フリーランスに関わらず、参画後に安心してご活躍できることを目指し、応募された方の特性・ご希望にマッチしたチームをご紹介します。
ちょっと話を聞いてみたい、ぜひ応募したい、など、当社にご興味を持っていただけましたら、お気軽にエントリーください!!