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; 024 025import javax.crypto.Cipher; 026import javax.crypto.NoSuchPaddingException; 027 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 JWS algorithm is supported by the default 063 * system JCA provider(s). 064 * 065 * @param alg The JWS algorithm. Must not be {@code null}. 066 * 067 * @return {@code true} if the JWS algorithm is supported, else 068 * {@code false}. 069 */ 070 public static boolean isSupported(final JWSAlgorithm alg) { 071 072 for (Provider p: Security.getProviders()) { 073 074 if (isSupported(alg, p)) { 075 return true; 076 } 077 } 078 079 return false; 080 } 081 082 083 /** 084 * Checks if a JWS algorithm is supported by the the specified JCA 085 * provider. 086 * 087 * @param alg The JWS algorithm. Must not be {@code null}. 088 * @param provider The JCA provider. Must not be {@code null}. 089 * 090 * @return {@code true} if the JWS algorithm is supported, else 091 * {@code false}. 092 */ 093 public static boolean isSupported(final JWSAlgorithm alg, final Provider provider) { 094 095 if (JWSAlgorithm.Family.HMAC_SHA.contains(alg)) { 096 String jcaName; 097 if (alg.equals(JWSAlgorithm.HS256)) { 098 jcaName = "HMACSHA256"; 099 } else if (alg.equals(JWSAlgorithm.HS384)) { 100 jcaName = "HMACSHA384"; 101 } else if (alg.equals(JWSAlgorithm.HS512)) { 102 jcaName = "HMACSHA512"; 103 } else { 104 return false; 105 } 106 return provider.getService("KeyGenerator", jcaName) != null; 107 } 108 109 if (JWSAlgorithm.Family.RSA.contains(alg)) { 110 String jcaName; 111 if (alg.equals(JWSAlgorithm.RS256)) { 112 jcaName = "SHA256withRSA"; 113 } else if (alg.equals(JWSAlgorithm.RS384)) { 114 jcaName = "SHA384withRSA"; 115 } else if (alg.equals(JWSAlgorithm.RS512)) { 116 jcaName = "SHA512withRSA"; 117 } else if (alg.equals(JWSAlgorithm.PS256)) { 118 jcaName = "SHA256withRSAandMGF1"; 119 } else if (alg.equals(JWSAlgorithm.PS384)) { 120 jcaName = "SHA384withRSAandMGF1"; 121 } else if (alg.equals(JWSAlgorithm.PS512)) { 122 jcaName = "SHA512withRSAandMGF1"; 123 } else { 124 return false; 125 } 126 return provider.getService("Signature", jcaName) != null; 127 } 128 129 if (JWSAlgorithm.Family.EC.contains(alg)) { 130 String jcaName; 131 if (alg.equals(JWSAlgorithm.ES256)) { 132 jcaName = "SHA256withECDSA"; 133 } else if (alg.equals(JWSAlgorithm.ES384)) { 134 jcaName = "SHA384withECDSA"; 135 } else if (alg.equals(JWSAlgorithm.ES512)) { 136 jcaName = "SHA512withECDSA"; 137 } else { 138 return false; 139 } 140 return provider.getService("Signature", jcaName) != null; 141 } 142 143 return false; 144 } 145 146 147 /** 148 * Checks if the specified JWE algorithm is supported by the default 149 * system JCA provider(s). 150 * 151 * @param alg The JWE algorithm. Must not be {@code null}. 152 * 153 * @return {@code true} if the JWE algorithm is supported, else 154 * {@code false}. 155 */ 156 public static boolean isSupported(final JWEAlgorithm alg) { 157 158 for (Provider p: Security.getProviders()) { 159 160 if (isSupported(alg, p)) { 161 return true; 162 } 163 } 164 165 return false; 166 } 167 168 169 /** 170 * Checks if a JWE algorithm is supported by the the specified JCA 171 * provider. 172 * 173 * @param alg The JWE algorithm. Must not be {@code null}. 174 * @param provider The JCA provider. Must not be {@code null}. 175 * 176 * @return {@code true} if the JWE algorithm is supported, else 177 * {@code false}. 178 */ 179 public static boolean isSupported(final JWEAlgorithm alg, final Provider provider) { 180 181 String jcaName; 182 183 if (JWEAlgorithm.Family.RSA.contains(alg)) { 184 if (alg.equals(JWEAlgorithm.RSA1_5)) { 185 jcaName = "RSA/ECB/PKCS1Padding"; 186 } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) { 187 jcaName = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; 188 } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) { 189 jcaName = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; 190 } else { 191 return false; 192 } 193 194 // Do direct test 195 try { 196 Cipher.getInstance(jcaName, provider); 197 } catch (NoSuchAlgorithmException e) { 198 return false; 199 } catch (NoSuchPaddingException e) { 200 return false; 201 } 202 return true; 203 } 204 205 if (JWEAlgorithm.Family.AES_KW.contains(alg)) { 206 return provider.getService("Cipher", "AESWrap") != null; 207 } 208 209 if (JWEAlgorithm.Family.ECDH_ES.contains(alg)) { 210 return provider.getService("KeyAgreement", "ECDH") != null; 211 } 212 213 if (JWEAlgorithm.Family.AES_GCM_KW.contains(alg)) { 214 // Do direct test 215 try { 216 Cipher.getInstance("AES/GCM/NoPadding", provider); 217 } catch (NoSuchAlgorithmException e) { 218 return false; 219 } catch (NoSuchPaddingException e) { 220 return false; 221 } 222 return true; 223 } 224 225 if (JWEAlgorithm.Family.PBES2.contains(alg)) { 226 String hmac; 227 if (alg.equals(JWEAlgorithm.PBES2_HS256_A128KW)) { 228 hmac = "HmacSHA256"; 229 } else if (alg.equals(JWEAlgorithm.PBES2_HS384_A192KW)) { 230 hmac = "HmacSHA384"; 231 } else { 232 hmac = "HmacSHA512"; 233 } 234 return provider.getService("KeyGenerator", hmac) != null; 235 } 236 237 if (JWEAlgorithm.DIR.equals(alg)) { 238 return true; // Always supported 239 } 240 241 return false; 242 } 243 244 245 /** 246 * Checks if the specified JWE encryption method is supported by the 247 * default system JCA provider(s). 248 * 249 * @param enc The JWE encryption method. Must not be {@code null}. 250 * 251 * @return {@code true} if the JWE algorithm is supported, else 252 * {@code false}. 253 */ 254 public static boolean isSupported(final EncryptionMethod enc) { 255 256 for (Provider p: Security.getProviders()) { 257 258 if (isSupported(enc, p)) { 259 return true; 260 } 261 } 262 263 return false; 264 } 265 266 267 /** 268 * Checks if a JWE encryption method is supported by the specified 269 * JCA provider. 270 * 271 * @param enc The JWE encryption method. Must not be {@code null}. 272 * @param provider The JCA provider. Must not be {@code null}. 273 * 274 * @return {@code true} if the JWE encryption method is supported, else 275 * {@code false}. 276 */ 277 public static boolean isSupported(final EncryptionMethod enc, final Provider provider) { 278 279 if (EncryptionMethod.Family.AES_CBC_HMAC_SHA.contains(enc)) { 280 // Do direct test 281 try { 282 Cipher.getInstance("AES/CBC/PKCS5Padding", provider); 283 } catch (NoSuchAlgorithmException e) { 284 return false; 285 } catch (NoSuchPaddingException e) { 286 return false; 287 } 288 // Check hmac 289 String hmac; 290 if (enc.equals(EncryptionMethod.A128CBC_HS256)) { 291 hmac = "HmacSHA256"; 292 } else if (enc.equals(EncryptionMethod.A192CBC_HS384)) { 293 hmac = "HmacSHA384"; 294 } else { 295 hmac = "HmacSHA512"; 296 } 297 return provider.getService("KeyGenerator", hmac) != null; 298 } 299 300 if (EncryptionMethod.Family.AES_GCM.contains(enc)) { 301 // Do direct test 302 try { 303 Cipher.getInstance("AES/GCM/NoPadding", provider); 304 } catch (NoSuchAlgorithmException e) { 305 return false; 306 } catch (NoSuchPaddingException e) { 307 return false; 308 } 309 return true; 310 } 311 312 return false; 313 } 314 315 316 /** 317 * Prevents public instantiation. 318 */ 319 private JCASupport() { 320 321 } 322}