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