1 /*
   2  * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @see SignUsingNONEwithRSA.sh
  26  */
  27 
  28 import java.security.*;
  29 import java.util.*;
  30 
  31 public class SignUsingNONEwithRSA {
  32 
  33     private static final List<byte[]> precomputedHashes = Arrays.asList(
  34         // A MD5 hash
  35         new byte[] {
  36             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
  37             0x11, 0x12, 0x13, 0x14, 0x15, 0x16
  38         },
  39         // A SHA-1 hash
  40         new byte[] {
  41             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
  42             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20
  43         },
  44         // A concatenation of SHA-1 and MD5 hashes (used during SSL handshake)
  45         new byte[] {
  46             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
  47             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
  48             0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
  49             0x31, 0x32, 0x33, 0x34, 0x35, 0x36
  50         },
  51         // A SHA-224 hash
  52         new byte[] {
  53             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
  54             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
  55             0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28
  56         },
  57         // A SHA-256 hash
  58         new byte[] {
  59             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
  60             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
  61             0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
  62             0x31, 0x32
  63         },
  64         // A SHA-384 hash
  65         new byte[] {
  66             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
  67             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
  68             0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
  69             0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40,
  70             0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48
  71         },
  72         // A SHA-512 hash
  73         new byte[] {
  74             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
  75             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
  76             0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
  77             0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40,
  78             0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50,
  79             0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60,
  80             0x61, 0x62, 0x63, 0x64
  81         });
  82 
  83     private static List<byte[]> generatedSignatures = new ArrayList<>();
  84 
  85     public static void main(String[] args) throws Exception {
  86 
  87         Provider[] providers = Security.getProviders("Signature.NONEwithRSA");
  88         if (providers == null) {
  89             System.out.println("No JCE providers support the " +
  90                 "'Signature.NONEwithRSA' algorithm");
  91             System.out.println("Skipping this test...");
  92             return;
  93 
  94         } else {
  95             System.out.println("The following JCE providers support the " +
  96                 "'Signature.NONEwithRSA' algorithm: ");
  97             for (Provider provider : providers) {
  98                 System.out.println("    " + provider.getName());
  99             }
 100         }
 101         System.out.println("-------------------------------------------------");
 102 
 103         KeyPair keys = getKeysFromKeyStore();
 104         signAllUsing("SunMSCAPI", keys.getPrivate());
 105         System.out.println("-------------------------------------------------");
 106 
 107         verifyAllUsing("SunMSCAPI", keys.getPublic());
 108         System.out.println("-------------------------------------------------");
 109 
 110         verifyAllUsing("SunJCE", keys.getPublic());
 111         System.out.println("-------------------------------------------------");
 112 
 113         keys = generateKeys();
 114         signAllUsing("SunJCE", keys.getPrivate());
 115         System.out.println("-------------------------------------------------");
 116 
 117         verifyAllUsing("SunMSCAPI", keys.getPublic());
 118         System.out.println("-------------------------------------------------");
 119 
 120     }
 121 
 122     private static KeyPair getKeysFromKeyStore() throws Exception {
 123         KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
 124         ks.load(null, null);
 125         System.out.println("Loaded keystore: Windows-MY");
 126 
 127         Enumeration e = ks.aliases();
 128         PrivateKey privateKey = null;
 129         PublicKey publicKey = null;
 130 
 131         while (e.hasMoreElements()) {
 132             String alias = (String) e.nextElement();
 133             if (alias.equals("6578658")) {
 134                 System.out.println("Loaded entry: " + alias);
 135                 privateKey = (PrivateKey) ks.getKey(alias, null);
 136                 publicKey = (PublicKey) ks.getCertificate(alias).getPublicKey();
 137             }
 138         }
 139         if (privateKey == null || publicKey == null) {
 140             throw new Exception("Cannot load the keys need to run this test");
 141         }
 142 
 143         return new KeyPair(publicKey, privateKey);
 144     }
 145 
 146 
 147     private static KeyPair generateKeys() throws Exception {
 148         KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
 149         keyGen.initialize(1024, null);
 150         KeyPair pair = keyGen.generateKeyPair();
 151         PrivateKey privateKey = pair.getPrivate();
 152         PublicKey publicKey = pair.getPublic();
 153 
 154         if (privateKey == null || publicKey == null) {
 155             throw new Exception("Cannot load the keys need to run this test");
 156         }
 157 
 158         return new KeyPair(publicKey, privateKey);
 159     }
 160 
 161     private static void signAllUsing(String providerName, PrivateKey privateKey)
 162             throws Exception {
 163         Signature sig1 = Signature.getInstance("NONEwithRSA", providerName);
 164         if (sig1 == null) {
 165             throw new Exception("'NONEwithRSA' is not supported");
 166         }
 167         if (sig1.getProvider() != null) {
 168             System.out.println("Using NONEwithRSA signer from the " +
 169                 sig1.getProvider().getName() + " JCE provider");
 170         } else {
 171             System.out.println(
 172                 "Using NONEwithRSA signer from the internal JCE provider");
 173         }
 174 
 175         System.out.println("Using key: " + privateKey);
 176         generatedSignatures.clear();
 177         for (byte[] hash : precomputedHashes) {
 178             sig1.initSign(privateKey);
 179             sig1.update(hash);
 180 
 181             try {
 182 
 183                 byte [] sigBytes = sig1.sign();
 184                 System.out.println("\nGenerated RSA signature over a " +
 185                     hash.length + "-byte hash (signature length: " +
 186                     sigBytes.length * 8 + " bits)");
 187                 System.out.println(String.format("0x%0" +
 188                     (sigBytes.length * 2) + "x",
 189                     new java.math.BigInteger(1, sigBytes)));
 190                 generatedSignatures.add(sigBytes);
 191 
 192             } catch (SignatureException se) {
 193                 System.out.println("Error generating RSA signature: " + se);
 194             }
 195         }
 196     }
 197 
 198     private static void verifyAllUsing(String providerName, PublicKey publicKey)
 199             throws Exception {
 200         Signature sig1 = Signature.getInstance("NONEwithRSA", providerName);
 201         if (sig1.getProvider() != null) {
 202             System.out.println("\nUsing NONEwithRSA verifier from the " +
 203                 sig1.getProvider().getName() + " JCE provider");
 204         } else {
 205             System.out.println(
 206                 "\nUsing NONEwithRSA verifier from the internal JCE provider");
 207         }
 208 
 209         System.out.println("Using key: " + publicKey);
 210 
 211         int i = 0;
 212         for (byte[] hash : precomputedHashes) {
 213 
 214             byte[] sigBytes = generatedSignatures.get(i++);
 215             System.out.println("\nVerifying RSA Signature over a " +
 216                 hash.length + "-byte hash (signature length: " +
 217                 sigBytes.length * 8 + " bits)");
 218             System.out.println(String.format("0x%0" +
 219                 (sigBytes.length * 2) + "x",
 220                 new java.math.BigInteger(1, sigBytes)));
 221 
 222             sig1.initVerify(publicKey);
 223             sig1.update(hash);
 224             if (sig1.verify(sigBytes)) {
 225                 System.out.println("Verify PASSED");
 226             } else {
 227                 throw new Exception("Verify FAILED");
 228             }
 229         }
 230     }
 231 }