001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2016, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose.jca; 019 020 021import java.security.NoSuchAlgorithmException; 022import java.security.Provider; 023import java.security.Security; 024import javax.crypto.Cipher; 025import javax.crypto.NoSuchPaddingException; 026 027import com.nimbusds.jose.Algorithm; 028import com.nimbusds.jose.EncryptionMethod; 029import com.nimbusds.jose.JWEAlgorithm; 030import com.nimbusds.jose.JWSAlgorithm; 031 032 033/** 034 * Java Cryptography Architecture (JCA) support helper. 035 */ 036public final class JCASupport { 037 038 039 /** 040 * Checks if unlimited cryptographic strength is supported. If not 041 * download the appropriate jurisdiction policy files for your Java 042 * edition: 043 * 044 * <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> 045 * 046 * <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> 047 * 048 * @return {@code true} if unlimited cryptographic strength is 049 * supported, {@code false} if not. 050 */ 051 public static boolean isUnlimitedStrength() { 052 053 try { 054 return Cipher.getMaxAllowedKeyLength("AES") >= 256; 055 } catch (NoSuchAlgorithmException e) { 056 return false; 057 } 058 } 059 060 061 /** 062 * Checks if the specified JOSE algorithm is supported by the default 063 * system JCA provider(s). 064 * 065 * @param alg The JOSE algorithm. Must not be {@code null}. 066 * 067 * @return {@code true} if the JOSE algorithm is supported, else 068 * {@code false}. 069 */ 070 public static boolean isSupported(final Algorithm alg) { 071 072 if (alg instanceof JWSAlgorithm) { 073 return isSupported((JWSAlgorithm)alg); 074 } 075 if (alg instanceof JWEAlgorithm) { 076 return isSupported((JWEAlgorithm)alg); 077 } 078 if (alg instanceof EncryptionMethod) { 079 return isSupported((EncryptionMethod)alg); 080 } 081 throw new IllegalArgumentException("Unexpected algorithm class: " + alg.getClass().getCanonicalName()); 082 } 083 084 085 /** 086 * Checks if a JOSE algorithm is supported by the the specified JCA 087 * provider. 088 * 089 * @param alg The JOSE algorithm. Must not be {@code null}. 090 * @param provider The JCA provider. Must not be {@code null}. 091 * 092 * @return {@code true} if the JOSE algorithm is supported, else 093 * {@code false}. 094 */ 095 public static boolean isSupported(final Algorithm alg, final Provider provider) { 096 097 if (alg instanceof JWSAlgorithm) { 098 return isSupported((JWSAlgorithm)alg, provider); 099 } 100 if (alg instanceof JWEAlgorithm) { 101 return isSupported((JWEAlgorithm)alg, provider); 102 } 103 if (alg instanceof EncryptionMethod) { 104 return isSupported((EncryptionMethod)alg, provider); 105 } 106 throw new IllegalArgumentException("Unexpected algorithm class: " + alg.getClass().getCanonicalName()); 107 } 108 109 110 /** 111 * Checks if the specified JWS algorithm is supported by the default 112 * system JCA provider(s). 113 * 114 * @param alg The JWS algorithm. Must not be {@code null}. 115 * 116 * @return {@code true} if the JWS algorithm is supported, else 117 * {@code false}. 118 */ 119 public static boolean isSupported(final JWSAlgorithm alg) { 120 121 if (alg.getName().equals(Algorithm.NONE.getName())) { 122 return true; 123 } 124 125 for (Provider p: Security.getProviders()) { 126 127 if (isSupported(alg, p)) { 128 return true; 129 } 130 } 131 132 return false; 133 } 134 135 136 /** 137 * Checks if a JWS algorithm is supported by the the specified JCA 138 * provider. 139 * 140 * @param alg The JWS algorithm. Must not be {@code null}. 141 * @param provider The JCA provider. Must not be {@code null}. 142 * 143 * @return {@code true} if the JWS algorithm is supported, else 144 * {@code false}. 145 */ 146 public static boolean isSupported(final JWSAlgorithm alg, final Provider provider) { 147 148 if (JWSAlgorithm.Family.HMAC_SHA.contains(alg)) { 149 String jcaName; 150 if (alg.equals(JWSAlgorithm.HS256)) { 151 jcaName = "HMACSHA256"; 152 } else if (alg.equals(JWSAlgorithm.HS384)) { 153 jcaName = "HMACSHA384"; 154 } else if (alg.equals(JWSAlgorithm.HS512)) { 155 jcaName = "HMACSHA512"; 156 } else { 157 return false; 158 } 159 return provider.getService("KeyGenerator", jcaName) != null; 160 } 161 162 if (JWSAlgorithm.Family.RSA.contains(alg)) { 163 String jcaName; 164 if (alg.equals(JWSAlgorithm.RS256)) { 165 jcaName = "SHA256withRSA"; 166 } else if (alg.equals(JWSAlgorithm.RS384)) { 167 jcaName = "SHA384withRSA"; 168 } else if (alg.equals(JWSAlgorithm.RS512)) { 169 jcaName = "SHA512withRSA"; 170 } else if (alg.equals(JWSAlgorithm.PS256)) { 171 jcaName = "SHA256withRSAandMGF1"; 172 } else if (alg.equals(JWSAlgorithm.PS384)) { 173 jcaName = "SHA384withRSAandMGF1"; 174 } else if (alg.equals(JWSAlgorithm.PS512)) { 175 jcaName = "SHA512withRSAandMGF1"; 176 } else { 177 return false; 178 } 179 return provider.getService("Signature", jcaName) != null; 180 } 181 182 if (JWSAlgorithm.Family.EC.contains(alg)) { 183 String jcaName; 184 if (alg.equals(JWSAlgorithm.ES256)) { 185 jcaName = "SHA256withECDSA"; 186 } else if (alg.equals(JWSAlgorithm.ES384)) { 187 jcaName = "SHA384withECDSA"; 188 } else if (alg.equals(JWSAlgorithm.ES512)) { 189 jcaName = "SHA512withECDSA"; 190 } else { 191 return false; 192 } 193 return provider.getService("Signature", jcaName) != null; 194 } 195 196 return false; 197 } 198 199 200 /** 201 * Checks if the specified JWE algorithm is supported by the default 202 * system JCA provider(s). 203 * 204 * @param alg The JWE algorithm. Must not be {@code null}. 205 * 206 * @return {@code true} if the JWE algorithm is supported, else 207 * {@code false}. 208 */ 209 public static boolean isSupported(final JWEAlgorithm alg) { 210 211 for (Provider p: Security.getProviders()) { 212 213 if (isSupported(alg, p)) { 214 return true; 215 } 216 } 217 218 return false; 219 } 220 221 222 /** 223 * Checks if a JWE algorithm is supported by the the specified JCA 224 * provider. 225 * 226 * @param alg The JWE algorithm. Must not be {@code null}. 227 * @param provider The JCA provider. Must not be {@code null}. 228 * 229 * @return {@code true} if the JWE algorithm is supported, else 230 * {@code false}. 231 */ 232 public static boolean isSupported(final JWEAlgorithm alg, final Provider provider) { 233 234 String jcaName; 235 236 if (JWEAlgorithm.Family.RSA.contains(alg)) { 237 if (alg.equals(JWEAlgorithm.RSA1_5)) { 238 jcaName = "RSA/ECB/PKCS1Padding"; 239 } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) { 240 jcaName = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; 241 } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) { 242 jcaName = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; 243 } else { 244 return false; 245 } 246 247 // Do direct test 248 try { 249 Cipher.getInstance(jcaName, provider); 250 } catch (NoSuchAlgorithmException e) { 251 return false; 252 } catch (NoSuchPaddingException e) { 253 return false; 254 } 255 return true; 256 } 257 258 if (JWEAlgorithm.Family.AES_KW.contains(alg)) { 259 return provider.getService("Cipher", "AESWrap") != null; 260 } 261 262 if (JWEAlgorithm.Family.ECDH_ES.contains(alg)) { 263 return provider.getService("KeyAgreement", "ECDH") != null; 264 } 265 266 if (JWEAlgorithm.Family.AES_GCM_KW.contains(alg)) { 267 // Do direct test 268 try { 269 Cipher.getInstance("AES/GCM/NoPadding", provider); 270 } catch (NoSuchAlgorithmException e) { 271 return false; 272 } catch (NoSuchPaddingException e) { 273 return false; 274 } 275 return true; 276 } 277 278 if (JWEAlgorithm.Family.PBES2.contains(alg)) { 279 String hmac; 280 if (alg.equals(JWEAlgorithm.PBES2_HS256_A128KW)) { 281 hmac = "HmacSHA256"; 282 } else if (alg.equals(JWEAlgorithm.PBES2_HS384_A192KW)) { 283 hmac = "HmacSHA384"; 284 } else { 285 hmac = "HmacSHA512"; 286 } 287 return provider.getService("KeyGenerator", hmac) != null; 288 } 289 290 if (JWEAlgorithm.DIR.equals(alg)) { 291 return true; // Always supported 292 } 293 294 return false; 295 } 296 297 298 /** 299 * Checks if the specified JWE encryption method is supported by the 300 * default system JCA provider(s). 301 * 302 * @param enc The JWE encryption method. Must not be {@code null}. 303 * 304 * @return {@code true} if the JWE algorithm is supported, else 305 * {@code false}. 306 */ 307 public static boolean isSupported(final EncryptionMethod enc) { 308 309 for (Provider p: Security.getProviders()) { 310 311 if (isSupported(enc, p)) { 312 return true; 313 } 314 } 315 316 return false; 317 } 318 319 320 /** 321 * Checks if a JWE encryption method is supported by the specified 322 * JCA provider. 323 * 324 * @param enc The JWE encryption method. Must not be {@code null}. 325 * @param provider The JCA provider. Must not be {@code null}. 326 * 327 * @return {@code true} if the JWE encryption method is supported, else 328 * {@code false}. 329 */ 330 public static boolean isSupported(final EncryptionMethod enc, final Provider provider) { 331 332 if (EncryptionMethod.Family.AES_CBC_HMAC_SHA.contains(enc)) { 333 // Do direct test 334 try { 335 Cipher.getInstance("AES/CBC/PKCS5Padding", provider); 336 } catch (NoSuchAlgorithmException e) { 337 return false; 338 } catch (NoSuchPaddingException e) { 339 return false; 340 } 341 // Check hmac 342 String hmac; 343 if (enc.equals(EncryptionMethod.A128CBC_HS256)) { 344 hmac = "HmacSHA256"; 345 } else if (enc.equals(EncryptionMethod.A192CBC_HS384)) { 346 hmac = "HmacSHA384"; 347 } else { 348 hmac = "HmacSHA512"; 349 } 350 return provider.getService("KeyGenerator", hmac) != null; 351 } 352 353 if (EncryptionMethod.Family.AES_GCM.contains(enc)) { 354 // Do direct test 355 try { 356 Cipher.getInstance("AES/GCM/NoPadding", provider); 357 } catch (NoSuchAlgorithmException e) { 358 return false; 359 } catch (NoSuchPaddingException e) { 360 return false; 361 } 362 return true; 363 } 364 365 return false; 366 } 367 368 369 /** 370 * Prevents public instantiation. 371 */ 372 private JCASupport() { 373 374 } 375}