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 return JWEAlgorithm.DIR.equals(alg); // Always supported 291 } 292 293 294 /** 295 * Checks if the specified JWE encryption method is supported by the 296 * default system JCA provider(s). 297 * 298 * @param enc The JWE encryption method. Must not be {@code null}. 299 * 300 * @return {@code true} if the JWE algorithm is supported, else 301 * {@code false}. 302 */ 303 public static boolean isSupported(final EncryptionMethod enc) { 304 305 for (Provider p: Security.getProviders()) { 306 307 if (isSupported(enc, p)) { 308 return true; 309 } 310 } 311 312 return false; 313 } 314 315 316 /** 317 * Checks if a JWE encryption method is supported by the specified 318 * JCA provider. 319 * 320 * @param enc The JWE encryption method. Must not be {@code null}. 321 * @param provider The JCA provider. Must not be {@code null}. 322 * 323 * @return {@code true} if the JWE encryption method is supported, else 324 * {@code false}. 325 */ 326 public static boolean isSupported(final EncryptionMethod enc, final Provider provider) { 327 328 if (EncryptionMethod.Family.AES_CBC_HMAC_SHA.contains(enc)) { 329 // Do direct test 330 try { 331 Cipher.getInstance("AES/CBC/PKCS5Padding", provider); 332 } catch (NoSuchAlgorithmException e) { 333 return false; 334 } catch (NoSuchPaddingException e) { 335 return false; 336 } 337 // Check hmac 338 String hmac; 339 if (enc.equals(EncryptionMethod.A128CBC_HS256)) { 340 hmac = "HmacSHA256"; 341 } else if (enc.equals(EncryptionMethod.A192CBC_HS384)) { 342 hmac = "HmacSHA384"; 343 } else { 344 hmac = "HmacSHA512"; 345 } 346 return provider.getService("KeyGenerator", hmac) != null; 347 } 348 349 if (EncryptionMethod.Family.AES_GCM.contains(enc)) { 350 // Do direct test 351 try { 352 Cipher.getInstance("AES/GCM/NoPadding", provider); 353 } catch (NoSuchAlgorithmException e) { 354 return false; 355 } catch (NoSuchPaddingException e) { 356 return false; 357 } 358 return true; 359 } 360 361 return false; 362 } 363 364 365 /** 366 * Prevents public instantiation. 367 */ 368 private JCASupport() { 369 370 } 371}