001package com.nimbusds.jose.jca; 002 003 004import java.security.NoSuchAlgorithmException; 005import java.security.Provider; 006import java.security.Security; 007 008import javax.crypto.Cipher; 009import javax.crypto.NoSuchPaddingException; 010 011import com.nimbusds.jose.EncryptionMethod; 012import com.nimbusds.jose.JWEAlgorithm; 013import com.nimbusds.jose.JWSAlgorithm; 014 015 016/** 017 * Java Cryptography Architecture (JCA) support helper. 018 */ 019public final class JCASupport { 020 021 022 /** 023 * Checks if unlimited cryptographic strength is supported. If not 024 * download the appropriate jurisdiction policy files for your Java 025 * edition: 026 * 027 * <p><a href="http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html">JCE Unlimited Strength Jurisdiction Policy Files for Java 7</a> 028 * 029 * <p><a href="http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html">JCE Unlimited Strength Jurisdiction Policy Files for Java 8</a> 030 * 031 * @return {@code true} if unlimited cryptographic strength is 032 * supported, {@code false} if not. 033 */ 034 public static boolean isUnlimitedStrength() { 035 036 try { 037 return Cipher.getMaxAllowedKeyLength("AES") >= 256; 038 } catch (NoSuchAlgorithmException e) { 039 return false; 040 } 041 } 042 043 044 /** 045 * Checks if the specified JWS algorithm is supported by the default 046 * system JCA provider(s). 047 * 048 * @param alg The JWS algorithm. Must not be {@code null}. 049 * 050 * @return {@code true} if the JWS algorithm is supported, else 051 * {@code false}. 052 */ 053 public static boolean isSupported(final JWSAlgorithm alg) { 054 055 for (Provider p: Security.getProviders()) { 056 057 if (isSupported(alg, p)) { 058 return true; 059 } 060 } 061 062 return false; 063 } 064 065 066 /** 067 * Checks if a JWS algorithm is supported by the the specified JCA 068 * provider. 069 * 070 * @param alg The JWS algorithm. Must not be {@code null}. 071 * @param provider The JCA provider. Must not be {@code null}. 072 * 073 * @return {@code true} if the JWS algorithm is supported, else 074 * {@code false}. 075 */ 076 public static boolean isSupported(final JWSAlgorithm alg, final Provider provider) { 077 078 if (JWSAlgorithm.Family.HMAC_SHA.contains(alg)) { 079 String jcaName; 080 if (alg.equals(JWSAlgorithm.HS256)) { 081 jcaName = "HMACSHA256"; 082 } else if (alg.equals(JWSAlgorithm.HS384)) { 083 jcaName = "HMACSHA384"; 084 } else if (alg.equals(JWSAlgorithm.HS512)) { 085 jcaName = "HMACSHA512"; 086 } else { 087 return false; 088 } 089 return provider.getService("KeyGenerator", jcaName) != null; 090 } 091 092 if (JWSAlgorithm.Family.RSA.contains(alg)) { 093 String jcaName; 094 if (alg.equals(JWSAlgorithm.RS256)) { 095 jcaName = "SHA256withRSA"; 096 } else if (alg.equals(JWSAlgorithm.RS384)) { 097 jcaName = "SHA384withRSA"; 098 } else if (alg.equals(JWSAlgorithm.RS512)) { 099 jcaName = "SHA512withRSA"; 100 } else if (alg.equals(JWSAlgorithm.PS256)) { 101 jcaName = "SHA256withRSAandMGF1"; 102 } else if (alg.equals(JWSAlgorithm.PS384)) { 103 jcaName = "SHA384withRSAandMGF1"; 104 } else if (alg.equals(JWSAlgorithm.PS512)) { 105 jcaName = "SHA512withRSAandMGF1"; 106 } else { 107 return false; 108 } 109 return provider.getService("Signature", jcaName) != null; 110 } 111 112 if (JWSAlgorithm.Family.EC.contains(alg)) { 113 String jcaName; 114 if (alg.equals(JWSAlgorithm.ES256)) { 115 jcaName = "SHA256withECDSA"; 116 } else if (alg.equals(JWSAlgorithm.ES384)) { 117 jcaName = "SHA384withECDSA"; 118 } else if (alg.equals(JWSAlgorithm.ES512)) { 119 jcaName = "SHA512withECDSA"; 120 } else { 121 return false; 122 } 123 return provider.getService("Signature", jcaName) != null; 124 } 125 126 return false; 127 } 128 129 130 /** 131 * Checks if the specified JWE algorithm is supported by the default 132 * system JCA provider(s). 133 * 134 * @param alg The JWE algorithm. Must not be {@code null}. 135 * 136 * @return {@code true} if the JWE algorithm is supported, else 137 * {@code false}. 138 */ 139 public static boolean isSupported(final JWEAlgorithm alg) { 140 141 for (Provider p: Security.getProviders()) { 142 143 if (isSupported(alg, p)) { 144 return true; 145 } 146 } 147 148 return false; 149 } 150 151 152 /** 153 * Checks if a JWE algorithm is supported by the the specified JCA 154 * provider. 155 * 156 * @param alg The JWE algorithm. Must not be {@code null}. 157 * @param provider The JCA provider. Must not be {@code null}. 158 * 159 * @return {@code true} if the JWE algorithm is supported, else 160 * {@code false}. 161 */ 162 public static boolean isSupported(final JWEAlgorithm alg, final Provider provider) { 163 164 String jcaName; 165 166 if (JWEAlgorithm.Family.RSA.contains(alg)) { 167 if (alg.equals(JWEAlgorithm.RSA1_5)) { 168 jcaName = "RSA/ECB/PKCS1Padding"; 169 } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) { 170 jcaName = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; 171 } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) { 172 jcaName = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; 173 } else { 174 return false; 175 } 176 177 // Do direct test 178 try { 179 Cipher.getInstance(jcaName, provider); 180 } catch (NoSuchAlgorithmException e) { 181 return false; 182 } catch (NoSuchPaddingException e) { 183 return false; 184 } 185 return true; 186 } 187 188 if (JWEAlgorithm.Family.AES_KW.contains(alg)) { 189 return provider.getService("Cipher", "AESWrap") != null; 190 } 191 192 if (JWEAlgorithm.Family.ECDH_ES.contains(alg)) { 193 return provider.getService("KeyAgreement", "ECDH") != null; 194 } 195 196 if (JWEAlgorithm.Family.AES_GCM_KW.contains(alg)) { 197 // Do direct test 198 try { 199 Cipher.getInstance("AES/GCM/NoPadding", provider); 200 } catch (NoSuchAlgorithmException e) { 201 return false; 202 } catch (NoSuchPaddingException e) { 203 return false; 204 } 205 return true; 206 } 207 208 if (JWEAlgorithm.Family.PBES2.contains(alg)) { 209 String hmac; 210 if (alg.equals(JWEAlgorithm.PBES2_HS256_A128KW)) { 211 hmac = "HmacSHA256"; 212 } else if (alg.equals(JWEAlgorithm.PBES2_HS384_A192KW)) { 213 hmac = "HmacSHA384"; 214 } else { 215 hmac = "HmacSHA512"; 216 } 217 return provider.getService("KeyGenerator", hmac) != null; 218 } 219 220 if (JWEAlgorithm.DIR.equals(alg)) { 221 return true; // Always supported 222 } 223 224 return false; 225 } 226 227 228 /** 229 * Checks if the specified JWE encryption method is supported by the 230 * default system JCA provider(s). 231 * 232 * @param enc The JWE encryption method. Must not be {@code null}. 233 * 234 * @return {@code true} if the JWE algorithm is supported, else 235 * {@code false}. 236 */ 237 public static boolean isSupported(final EncryptionMethod enc) { 238 239 for (Provider p: Security.getProviders()) { 240 241 if (isSupported(enc, p)) { 242 return true; 243 } 244 } 245 246 return false; 247 } 248 249 250 /** 251 * Checks if a JWE encryption method is supported by the specified 252 * JCA provider. 253 * 254 * @param enc The JWE encryption method. Must not be {@code null}. 255 * @param provider The JCA provider. Must not be {@code null}. 256 * 257 * @return {@code true} if the JWE encryption method is supported, else 258 * {@code false}. 259 */ 260 public static boolean isSupported(final EncryptionMethod enc, final Provider provider) { 261 262 if (EncryptionMethod.Family.AES_CBC_HMAC_SHA.contains(enc)) { 263 // Do direct test 264 try { 265 Cipher.getInstance("AES/CBC/PKCS5Padding", provider); 266 } catch (NoSuchAlgorithmException e) { 267 return false; 268 } catch (NoSuchPaddingException e) { 269 return false; 270 } 271 // Check hmac 272 String hmac; 273 if (enc.equals(EncryptionMethod.A128CBC_HS256)) { 274 hmac = "HmacSHA256"; 275 } else if (enc.equals(EncryptionMethod.A192CBC_HS384)) { 276 hmac = "HmacSHA384"; 277 } else { 278 hmac = "HmacSHA512"; 279 } 280 return provider.getService("KeyGenerator", hmac) != null; 281 } 282 283 if (EncryptionMethod.Family.AES_GCM.contains(enc)) { 284 // Do direct test 285 try { 286 Cipher.getInstance("AES/GCM/NoPadding", provider); 287 } catch (NoSuchAlgorithmException e) { 288 return false; 289 } catch (NoSuchPaddingException e) { 290 return false; 291 } 292 return true; 293 } 294 295 return false; 296 } 297 298 299 /** 300 * Prevents public instantiation. 301 */ 302 private JCASupport() { 303 304 } 305}