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.Mac; 026import javax.crypto.NoSuchPaddingException; 027 028import com.nimbusds.jose.*; 029import com.nimbusds.jose.crypto.impl.ECDSA; 030import com.nimbusds.jose.crypto.impl.RSASSA; 031 032 033/** 034 * Java Cryptography Architecture (JCA) support helper. 035 * 036 * @version 2022-05-16 037 */ 038public final class JCASupport { 039 040 041 /** 042 * Checks if unlimited cryptographic strength is supported. If not 043 * download the appropriate jurisdiction policy files for your Java 044 * edition: 045 * 046 * <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> 047 * 048 * <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> 049 * 050 * @return {@code true} if unlimited cryptographic strength is 051 * supported, {@code false} if not. 052 */ 053 public static boolean isUnlimitedStrength() { 054 055 try { 056 return Cipher.getMaxAllowedKeyLength("AES") >= 256; 057 } catch (NoSuchAlgorithmException e) { 058 return false; 059 } 060 } 061 062 063 /** 064 * Checks if the specified JOSE algorithm is supported by the default 065 * system JCA provider(s). 066 * 067 * @param alg The JOSE algorithm. Must not be {@code null}. 068 * 069 * @return {@code true} if the JOSE algorithm is supported, else 070 * {@code false}. 071 */ 072 public static boolean isSupported(final Algorithm alg) { 073 074 if (alg instanceof JWSAlgorithm) { 075 return isSupported((JWSAlgorithm)alg); 076 } 077 if (alg instanceof JWEAlgorithm) { 078 return isSupported((JWEAlgorithm)alg); 079 } 080 if (alg instanceof EncryptionMethod) { 081 return isSupported((EncryptionMethod)alg); 082 } 083 throw new IllegalArgumentException("Unexpected algorithm class: " + alg.getClass().getCanonicalName()); 084 } 085 086 087 /** 088 * Checks if a JOSE algorithm is supported by the specified JCA 089 * provider. 090 * 091 * @param alg The JOSE algorithm. Must not be {@code null}. 092 * @param provider The JCA provider. Must not be {@code null}. 093 * 094 * @return {@code true} if the JOSE algorithm is supported, else 095 * {@code false}. 096 */ 097 public static boolean isSupported(final Algorithm alg, final Provider provider) { 098 099 if (alg instanceof JWSAlgorithm) { 100 return isSupported((JWSAlgorithm)alg, provider); 101 } 102 if (alg instanceof JWEAlgorithm) { 103 return isSupported((JWEAlgorithm)alg, provider); 104 } 105 if (alg instanceof EncryptionMethod) { 106 return isSupported((EncryptionMethod)alg, provider); 107 } 108 throw new IllegalArgumentException("Unexpected algorithm class: " + alg.getClass().getCanonicalName()); 109 } 110 111 112 /** 113 * Checks if the specified JWS algorithm is supported by the default 114 * system JCA provider(s). 115 * 116 * @param alg The JWS algorithm. Must not be {@code null}. 117 * 118 * @return {@code true} if the JWS algorithm is supported, else 119 * {@code false}. 120 */ 121 public static boolean isSupported(final JWSAlgorithm alg) { 122 123 if (alg.getName().equals(Algorithm.NONE.getName())) { 124 return true; 125 } 126 127 for (Provider p: Security.getProviders()) { 128 129 if (isSupported(alg, p)) { 130 return true; 131 } 132 } 133 134 return false; 135 } 136 137 138 /** 139 * Checks if a JWS algorithm is supported by the specified JCA 140 * provider. 141 * 142 * @param alg The JWS algorithm. Must not be {@code null}. 143 * @param provider The JCA provider. Must not be {@code null}. 144 * 145 * @return {@code true} if the JWS algorithm is supported, else 146 * {@code false}. 147 */ 148 public static boolean isSupported(final JWSAlgorithm alg, final Provider provider) { 149 150 if (JWSAlgorithm.Family.HMAC_SHA.contains(alg)) { 151 String jcaName; 152 if (alg.equals(JWSAlgorithm.HS256)) { 153 jcaName = "HMACSHA256"; 154 } else if (alg.equals(JWSAlgorithm.HS384)) { 155 jcaName = "HMACSHA384"; 156 } else if (alg.equals(JWSAlgorithm.HS512)) { 157 jcaName = "HMACSHA512"; 158 } else { 159 return false; 160 } 161 try { 162 Mac.getInstance(jcaName, provider); 163 } catch (NoSuchAlgorithmException e) { 164 return false; 165 } 166 return true; 167 } 168 169 if (JWSAlgorithm.Family.RSA.contains(alg)) { 170 try { 171 RSASSA.getSignerAndVerifier(alg, provider); 172 } catch (JOSEException e) { 173 return false; 174 } 175 return true; 176 } 177 178 if (JWSAlgorithm.Family.EC.contains(alg)) { 179 try { 180 ECDSA.getSignerAndVerifier(alg, provider); 181 } catch (JOSEException e) { 182 return false; 183 } 184 return true; 185 } 186 187 return false; 188 } 189 190 191 /** 192 * Checks if the specified JWE algorithm is supported by the default 193 * system JCA provider(s). 194 * 195 * @param alg The JWE algorithm. Must not be {@code null}. 196 * 197 * @return {@code true} if the JWE algorithm is supported, else 198 * {@code false}. 199 */ 200 public static boolean isSupported(final JWEAlgorithm alg) { 201 202 for (Provider p: Security.getProviders()) { 203 204 if (isSupported(alg, p)) { 205 return true; 206 } 207 } 208 209 return false; 210 } 211 212 213 /** 214 * Checks if a JWE algorithm is supported by the specified JCA 215 * provider. 216 * 217 * @param alg The JWE algorithm. Must not be {@code null}. 218 * @param provider The JCA provider. Must not be {@code null}. 219 * 220 * @return {@code true} if the JWE algorithm is supported, else 221 * {@code false}. 222 */ 223 public static boolean isSupported(final JWEAlgorithm alg, final Provider provider) { 224 225 String jcaName; 226 227 if (JWEAlgorithm.Family.RSA.contains(alg)) { 228 if (alg.equals(JWEAlgorithm.RSA1_5)) { 229 jcaName = "RSA/ECB/PKCS1Padding"; 230 } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) { 231 jcaName = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; 232 } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) { 233 jcaName = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; 234 } else if (alg.equals(JWEAlgorithm.RSA_OAEP_512)) { 235 jcaName = "RSA/ECB/OAEPWithSHA-512AndMGF1Padding"; 236 } else { 237 return false; 238 } 239 240 // Do direct test 241 try { 242 Cipher.getInstance(jcaName, provider); 243 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 244 return false; 245 } 246 return true; 247 } 248 249 if (JWEAlgorithm.Family.AES_KW.contains(alg)) { 250 return provider.getService("Cipher", "AESWrap") != null; 251 } 252 253 if (JWEAlgorithm.Family.ECDH_ES.contains(alg)) { 254 return provider.getService("KeyAgreement", "ECDH") != null; 255 } 256 257 if (JWEAlgorithm.Family.AES_GCM_KW.contains(alg)) { 258 // Do direct test 259 try { 260 Cipher.getInstance("AES/GCM/NoPadding", provider); 261 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 262 return false; 263 } 264 return true; 265 } 266 267 if (JWEAlgorithm.Family.PBES2.contains(alg)) { 268 String hmac; 269 if (alg.equals(JWEAlgorithm.PBES2_HS256_A128KW)) { 270 hmac = "HmacSHA256"; 271 } else if (alg.equals(JWEAlgorithm.PBES2_HS384_A192KW)) { 272 hmac = "HmacSHA384"; 273 } else { 274 hmac = "HmacSHA512"; 275 } 276 return provider.getService("KeyGenerator", hmac) != null; 277 } 278 279 return JWEAlgorithm.DIR.equals(alg); // Always supported 280 } 281 282 283 /** 284 * Checks if the specified JWE encryption method is supported by the 285 * default system JCA provider(s). 286 * 287 * @param enc The JWE encryption method. Must not be {@code null}. 288 * 289 * @return {@code true} if the JWE algorithm is supported, else 290 * {@code false}. 291 */ 292 public static boolean isSupported(final EncryptionMethod enc) { 293 294 for (Provider p: Security.getProviders()) { 295 296 if (isSupported(enc, p)) { 297 return true; 298 } 299 } 300 301 return false; 302 } 303 304 305 /** 306 * Checks if a JWE encryption method is supported by the specified 307 * JCA provider. 308 * 309 * @param enc The JWE encryption method. Must not be {@code null}. 310 * @param provider The JCA provider. Must not be {@code null}. 311 * 312 * @return {@code true} if the JWE encryption method is supported, else 313 * {@code false}. 314 */ 315 public static boolean isSupported(final EncryptionMethod enc, final Provider provider) { 316 317 if (EncryptionMethod.Family.AES_CBC_HMAC_SHA.contains(enc)) { 318 // Do direct test 319 try { 320 Cipher.getInstance("AES/CBC/PKCS5Padding", provider); 321 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 322 return false; 323 } 324 // Check hmac 325 String hmac; 326 if (enc.equals(EncryptionMethod.A128CBC_HS256)) { 327 hmac = "HmacSHA256"; 328 } else if (enc.equals(EncryptionMethod.A192CBC_HS384)) { 329 hmac = "HmacSHA384"; 330 } else { 331 hmac = "HmacSHA512"; 332 } 333 return provider.getService("KeyGenerator", hmac) != null; 334 } 335 336 if (EncryptionMethod.Family.AES_GCM.contains(enc)) { 337 // Do direct test 338 try { 339 Cipher.getInstance("AES/GCM/NoPadding", provider); 340 } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 341 return false; 342 } 343 return true; 344 } 345 346 return false; 347 } 348 349 350 /** 351 * Prevents public instantiation. 352 */ 353 private JCASupport() { 354 355 } 356}