001package com.nimbusds.jose.jca; 002 003 004import java.security.NoSuchAlgorithmException; 005import java.security.Provider; 006import java.security.Security; 007 008import javax.crypto.Cipher; 009import javax.crypto.NoSuchPaddingException; 010 011import com.nimbusds.jose.EncryptionMethod; 012import com.nimbusds.jose.JWEAlgorithm; 013import com.nimbusds.jose.JWSAlgorithm; 014 015 016/** 017 * Java Cryptography Architecture (JCA) support helper. 018 */ 019public final class JCASupport { 020 021 022 /** 023 * Checks if the specified JWS algorithm is supported by the default 024 * system JCA provider(s). 025 * 026 * @param alg The JWS algorithm. Must not be {@code null}. 027 * 028 * @return {@code true} if the JWS algorithm is supported, else 029 * {@code false}. 030 */ 031 public static boolean isSupported(final JWSAlgorithm alg) { 032 033 for (Provider p: Security.getProviders()) { 034 035 if (isSupported(alg, p)) { 036 return true; 037 } 038 } 039 040 return false; 041 } 042 043 044 /** 045 * Checks if a JWS algorithm is supported by the the specified JCA 046 * provider. 047 * 048 * @param alg The JWS algorithm. Must not be {@code null}. 049 * @param provider The JCA provider. Must not be {@code null}. 050 * 051 * @return {@code true} if the JWS algorithm is supported, else 052 * {@code false}. 053 */ 054 public static boolean isSupported(final JWSAlgorithm alg, final Provider provider) { 055 056 if (JWSAlgorithm.Family.HMAC_SHA.contains(alg)) { 057 String jcaName; 058 if (alg.equals(JWSAlgorithm.HS256)) { 059 jcaName = "HMACSHA256"; 060 } else if (alg.equals(JWSAlgorithm.HS384)) { 061 jcaName = "HMACSHA384"; 062 } else if (alg.equals(JWSAlgorithm.HS512)) { 063 jcaName = "HMACSHA512"; 064 } else { 065 return false; 066 } 067 return provider.getService("KeyGenerator", jcaName) != null; 068 } 069 070 if (JWSAlgorithm.Family.RSA.contains(alg)) { 071 String jcaName; 072 if (alg.equals(JWSAlgorithm.RS256)) { 073 jcaName = "SHA256withRSA"; 074 } else if (alg.equals(JWSAlgorithm.RS384)) { 075 jcaName = "SHA384withRSA"; 076 } else if (alg.equals(JWSAlgorithm.RS512)) { 077 jcaName = "SHA512withRSA"; 078 } else if (alg.equals(JWSAlgorithm.PS256)) { 079 jcaName = "SHA256withRSAandMGF1"; 080 } else if (alg.equals(JWSAlgorithm.PS384)) { 081 jcaName = "SHA384withRSAandMGF1"; 082 } else if (alg.equals(JWSAlgorithm.PS512)) { 083 jcaName = "SHA512withRSAandMGF1"; 084 } else { 085 return false; 086 } 087 return provider.getService("Signature", jcaName) != null; 088 } 089 090 if (JWSAlgorithm.Family.EC.contains(alg)) { 091 String jcaName; 092 if (alg.equals(JWSAlgorithm.ES256)) { 093 jcaName = "SHA256withECDSA"; 094 } else if (alg.equals(JWSAlgorithm.ES384)) { 095 jcaName = "SHA384withECDSA"; 096 } else if (alg.equals(JWSAlgorithm.ES512)) { 097 jcaName = "SHA512withECDSA"; 098 } else { 099 return false; 100 } 101 return provider.getService("Signature", jcaName) != null; 102 } 103 104 return false; 105 } 106 107 108 /** 109 * Checks if the specified JWE algorithm is supported by the default 110 * system JCA provider(s). 111 * 112 * @param alg The JWE algorithm. Must not be {@code null}. 113 * 114 * @return {@code true} if the JWE algorithm is supported, else 115 * {@code false}. 116 */ 117 public static boolean isSupported(final JWEAlgorithm alg) { 118 119 for (Provider p: Security.getProviders()) { 120 121 if (isSupported(alg, p)) { 122 return true; 123 } 124 } 125 126 return false; 127 } 128 129 130 /** 131 * Checks if a JWE algorithm is supported by the the specified JCA 132 * provider. 133 * 134 * @param alg The JWE algorithm. Must not be {@code null}. 135 * @param provider The JCA provider. Must not be {@code null}. 136 * 137 * @return {@code true} if the JWE algorithm is supported, else 138 * {@code false}. 139 */ 140 public static boolean isSupported(final JWEAlgorithm alg, final Provider provider) { 141 142 String jcaName; 143 144 if (JWEAlgorithm.Family.RSA.contains(alg)) { 145 if (alg.equals(JWEAlgorithm.RSA1_5)) { 146 jcaName = "RSA/ECB/PKCS1Padding"; 147 } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) { 148 jcaName = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; 149 } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) { 150 jcaName = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; 151 } else { 152 return false; 153 } 154 155 // Do direct test 156 try { 157 Cipher.getInstance(jcaName, provider); 158 } catch (NoSuchAlgorithmException e) { 159 return false; 160 } catch (NoSuchPaddingException e) { 161 return false; 162 } 163 return true; 164 } 165 166 if (JWEAlgorithm.Family.AES_KW.contains(alg)) { 167 return provider.getService("Cipher", "AESWrap") != null; 168 } 169 170 if (JWEAlgorithm.Family.ECDH_ES.contains(alg)) { 171 return provider.getService("KeyAgreement", "ECDH") != null; 172 } 173 174 if (JWEAlgorithm.Family.AES_GCM_KW.contains(alg)) { 175 // Do direct test 176 try { 177 Cipher.getInstance("AES/GCM/NoPadding", provider); 178 } catch (NoSuchAlgorithmException e) { 179 return false; 180 } catch (NoSuchPaddingException e) { 181 return false; 182 } 183 return true; 184 } 185 186 if (JWEAlgorithm.Family.PBES2.contains(alg)) { 187 String hmac; 188 if (alg.equals(JWEAlgorithm.PBES2_HS256_A128KW)) { 189 hmac = "HmacSHA256"; 190 } else if (alg.equals(JWEAlgorithm.PBES2_HS384_A192KW)) { 191 hmac = "HmacSHA384"; 192 } else { 193 hmac = "HmacSHA512"; 194 } 195 return provider.getService("KeyGenerator", hmac) != null; 196 } 197 198 return false; 199 } 200 201 202 /** 203 * Checks if the specified JWE encryption method is supported by the 204 * default system JCA provider(s). 205 * 206 * @param enc The JWE encryption method. Must not be {@code null}. 207 * 208 * @return {@code true} if the JWE algorithm is supported, else 209 * {@code false}. 210 */ 211 public static boolean isSupported(final EncryptionMethod enc) { 212 213 for (Provider p: Security.getProviders()) { 214 215 if (isSupported(enc, p)) { 216 return true; 217 } 218 } 219 220 return false; 221 } 222 223 224 /** 225 * Checks if a JWE encryption method is supported by the specified 226 * JCA provider. 227 * 228 * @param enc The JWE encryption method. Must not be {@code null}. 229 * @param provider The JCA provider. Must not be {@code null}. 230 * 231 * @return {@code true} if the JWE encryption method is supported, else 232 * {@code false}. 233 */ 234 public static boolean isSupported(final EncryptionMethod enc, final Provider provider) { 235 236 if (EncryptionMethod.Family.AES_CBC_HMAC_SHA.contains(enc)) { 237 // Do direct test 238 try { 239 Cipher.getInstance("AES/CBC/PKCS5Padding", provider); 240 } catch (NoSuchAlgorithmException e) { 241 return false; 242 } catch (NoSuchPaddingException e) { 243 return false; 244 } 245 // Check hmac 246 String hmac; 247 if (enc.equals(EncryptionMethod.A128CBC_HS256)) { 248 hmac = "HmacSHA256"; 249 } else if (enc.equals(EncryptionMethod.A192CBC_HS384)) { 250 hmac = "HmacSHA384"; 251 } else { 252 hmac = "HmacSHA512"; 253 } 254 return provider.getService("KeyGenerator", hmac) != null; 255 } 256 257 if (EncryptionMethod.Family.AES_GCM.contains(enc)) { 258 // Do direct test 259 try { 260 Cipher.getInstance("AES/GCM/NoPadding", provider); 261 } catch (NoSuchAlgorithmException e) { 262 return false; 263 } catch (NoSuchPaddingException e) { 264 return false; 265 } 266 return true; 267 } 268 269 return false; 270 } 271 272 273 /** 274 * Prevents public instantiation. 275 */ 276 private JCASupport() { 277 278 } 279}