見出し画像

XMLのデジタル署名をJavaで実装する

こんにちは。株式会社レスキューナウで基幹システムを担当しているエンジニアです。
今回はXMLのデジタル署名をJavaで実装した時のお話です。

デジタル署名とは、データの改ざんや作成者のなりすまし等を防ぐ為に付けられる、暗号化された電子的な署名です。

XMLデジタル署名の仕様は、W3C(World Wide Web Consortium)とIETF(Internet Engineering Task Force) により標準化されています。


XML署名の種類

XMLのデジタル署名には次の種類があります。

1. Detached 署名
 XML署名と対象文書が独立している形式
2. Enveloped 署名
 対象文書の中にXML署名を格納した形式
3. Enveloping 署名
 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

生成された鍵ファイル
testSignature.crt  X.509公開鍵証明書(RSA・SHA-256)testSignature.pem PEM形式の秘密鍵
testSignature.pk8  PKCS #8形式の秘密鍵


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>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
            VBVkYzH6RmJeCGjVAcJ/Qis=
        </X509Certificate>
      </X509Data>
    </KeyInfo>
  </Signature>
</data>


まとめ

これで、デジタル署名付きXMLの完成です。
最後までご覧いただき、ありがとうございました。

最後に

現在、レスキューナウでは、災害情報の提供、災害情報を活用した安否確認サービスなどのWebサービスの開発エンジニアを募集しています!
社員・フリーランスに関わらず、参画後に安心してご活躍できることを目指し、応募された方の特性・ご希望にマッチしたチームをご紹介します。
ちょっと話を聞いてみたい、ぜひ応募したい、など、当社にご興味を持っていただけましたら、お気軽にエントリーください!!