001/** 002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 003 * 004 * Copyright (c) 2007 Sun Microsystems Inc. All Rights Reserved 005 * 006 * The contents of this file are subject to the terms 007 * of the Common Development and Distribution License 008 * (the License). You may not use this file except in 009 * compliance with the License. 010 * 011 * You can obtain a copy of the License at 012 * https://opensso.dev.java.net/public/CDDLv1.0.html or 013 * opensso/legal/CDDLv1.0.txt 014 * See the License for the specific language governing 015 * permission and limitations under the License. 016 * 017 * When distributing Covered Code, include this CDDL 018 * Header Notice in each file and include the License file 019 * at opensso/legal/CDDLv1.0.txt. 020 * If applicable, add the following below the CDDL Header, 021 * with the fields enclosed by brackets [] replaced by 022 * your own identifying information: 023 * "Portions Copyrighted [year] [name of copyright owner]" 024 * 025 * $Id: SecureAttrs.java,v 1.12 2009/03/31 17:18:10 exu Exp $ 026 * 027 */ 028 029package com.sun.identity.sae.api; 030 031 032import java.util.*; 033import java.io.*; 034import java.io.UnsupportedEncodingException; 035import java.security.MessageDigest; 036import java.security.NoSuchAlgorithmException; 037import sun.misc.CharacterEncoder; 038import com.sun.identity.shared.encode.Base64; 039import com.sun.identity.security.DataEncryptor; 040import java.security.*; 041import java.security.cert.X509Certificate; 042 043/** 044 * <code>SecureAttrs</code> class forms the core api of "Secure Attributes 045 * Exchange" (SAE) feature. The class uses off the shelf digital 046 * signing and encryption algorithms to generate tamperproof/nonrepudiable 047 * strings representing attribute maps and to verify these strings. 048 * Typical SAE usage is to securely send attributes (authentication & 049 * use profile data) from an asserting application (eg running on an IDP) to 050 * a relying application (eg running on an SP). In this scenario the 051 * asserting party uses the "signing" interfaces to generate secure 052 * data and the relying application uses "verification" interfaces 053 * to ascertain the authenticity of the data. 054 * Current implementation provides two mechanisms to secure attributes : 055 * Symmetric : uses simple shared secrets between the two ends. 056 * Asymmetric : uses PKI based signing using public-private keys. 057 * Freshness is provided by a varying seed generated from the 058 * current timestamp and a configurable expiry period within which 059 * the relying party must validate the token. 060 * @supported.api 061 */ 062public class SecureAttrs 063{ 064 /** 065 * HTTP parameter name used to send and receive secure attribute data. 066 * IDP : sends secure attrs in this parameter. 067 * SP : receives secure attrs in this parameter. 068 * @supported.api 069 */ 070 public static final String SAE_PARAM_DATA = "sun.data"; 071 072 /** 073 * SAE Parameter representing a command. 074 * Currently only "logout" needs to be explicitly provided. SSO is implied. 075 * IDP : Uses this parameter to instruct FM to issue a global logout. 076 * SP : Receives this parameter from FM. 077 * @supported.api 078 */ 079 080 public static final String SAE_PARAM_CMD = "sun.cmd"; 081 082 /** 083 * SAE Parameter representing the authenticated user. 084 * IDP : Uses this parameter to send authenticated userid to FM. 085 * SP : Receives userid in this parameter. 086 * @supported.api 087 */ 088 public static final String SAE_PARAM_USERID = "sun.userid"; 089 090 /** 091 * SAE Parameter representing the session's authentication level. 092 * IDP : Uses this parameter to send authentication level to FM. 093 * SP : Receives authentication level in this parameter. 094 * @supported.api 095 */ 096 public static final String SAE_PARAM_AUTHLEVEL = "sun.authlevel"; 097 098 /** 099 * SAE Parameter used to pass IDP entity ID to SP app. 100 * IDP: Not Applicable 101 * SP: populates this parameter to identify IDP used in SSO. 102 */ 103 public static final String SAE_PARAM_IDPENTITYID = "sun.idpentityid"; 104 105 /** 106 * SAE Parameter used to pass SP entity ID to SP app. 107 * IDP: Not Applicable 108 * SP: populates this parameter to identify SP used in SSO. 109 */ 110 public static final String SAE_PARAM_SPENTITYID = "sun.spentityid"; 111 112 /** 113 * SAE Parameter representing the requested SP app to be invoked. 114 * IDP : populates this parameter with SP side app to be invoked. 115 * SP : Not Applicable. 116 * @supported.api 117 */ 118 public static final String SAE_PARAM_SPAPPURL = "sun.spappurl"; 119 120 /** 121 * SAE Parameter used to identify the IDP app (Asserting party) 122 * IDP : populates this parameter to identify itself. 123 * SP : Not Applicable. 124 * @supported.api 125 */ 126 public static final String SAE_PARAM_IDPAPPURL = "sun.idpappurl"; 127 128 /** 129 * SAE Parameter : Deprecated. 130 * @supported.api 131 */ 132 public static final String SAE_PARAM_APPID = "sun.appid"; 133 134 /** 135 * SAE Parameter internally used by FM for storing token timestamp. 136 * @supported.api 137 */ 138 public static final String SAE_PARAM_TS = "sun.ts"; 139 140 /** 141 * SAE Parameter internally used by FM for storing signature data. 142 * @supported.api 143 */ 144 public static final String SAE_PARAM_SIGN = "sun.sign"; 145 146 /** 147 * SAE Parameter used to comunicate errors. 148 * @supported.api 149 */ 150 public static final String SAE_PARAM_ERROR = "sun.error"; 151 152 /** 153 * SAE Parameter used to communicate to SP to return to specified url 154 * upon Logout completion. 155 * IDP : Not applicable 156 * SP : expected to redirect to the value upon processing logout req. 157 * @supported.api 158 */ 159 public static final String SAE_PARAM_APPSLORETURNURL = "sun.returnurl"; 160 161 /** 162 * SAE Parameter used to comunicate to FM where to redirect after a 163 * global logout is completed. 164 * IDP : sends this param as part of logout command. 165 * SP : N/A. 166 * @supported.api 167 */ 168 public static final String SAE_PARAM_APPRETURN = "sun.appreturn"; 169 170 /** 171 * SAE command <code>SAE_PARAM_CMD</code> 172 * @supported.api 173 */ 174 public static final String SAE_CMD_LOGOUT = "logout"; 175 176 /** 177 * Crypto types supported. 178 * @supported.api 179 */ 180 public static final String SAE_CRYPTO_TYPE = "type"; 181 182 /** 183 * Crypto type : Symmetric : shared secret based trust between parties. 184 * @supported.api 185 */ 186 public static final String SAE_CRYPTO_TYPE_ASYM = "asymmetric"; 187 188 /** 189 * Crypto type : Asymmetric : PKI based trust. 190 * @supported.api 191 */ 192 public static final String SAE_CRYPTO_TYPE_SYM = "symmetric"; 193 194 /** 195 * SAE Config : classame implementing <code>Cert</code>. 196 * If not specified, a JKS keystore default impl is used. 197 */ 198 public static final String SAE_CONFIG_CERT_CLASS = "certclassimpl"; 199 200 /** 201 * SAE Config : Location of the keystore to access keys from for 202 * asymmetric crypto. 203 * @supported.api 204 */ 205 public static final String SAE_CONFIG_KEYSTORE_FILE = "keystorefile"; 206 207 /** 208 * SAE Config : keystore type. Default : JKS 209 * @supported.api 210 */ 211 public static final String SAE_CONFIG_KEYSTORE_TYPE = "keystoretype"; 212 213 /** 214 * SAE Config : Password to open the keystrore. 215 * @supported.api 216 */ 217 public static final String SAE_CONFIG_KEYSTORE_PASS = "keystorepass"; 218 219 /** 220 * SAE Config : Private key alias for asymmetric signing. Alias 221 * is used to retrive the key from the keystore. 222 * @supported.api 223 */ 224 public static final String SAE_CONFIG_PRIVATE_KEY_ALIAS = "privatekeyalias"; 225 226 /** 227 * SAE Config : Public key for asymmetric signature verification. Alias 228 * is used to retrive the key from the keystore. 229 * @supported.api 230 */ 231 public static final String SAE_CONFIG_PUBLIC_KEY_ALIAS = "pubkeyalias"; 232 233 /** 234 * SAE Config : Private key for asymmetric signing. 235 * @supported.api 236 */ 237 public static final String SAE_CONFIG_PRIVATE_KEY = "privatekey"; 238 239 /** 240 * SAE Config : Password to access the private key. 241 * @supported.api 242 */ 243 public static final String SAE_CONFIG_PRIVATE_KEY_PASS = "privatekeypass"; 244 245 /** 246 * SAE Config : Flag to indicate whether keys should be cached in memory 247 * once retrieved from the keystore. 248 * @supported.api 249 */ 250 public static final String SAE_CONFIG_CACHE_KEYS = "cachekeys"; 251 252 /** 253 * SAE Config : shared secret constant - used internally in FM. 254 * @supported.api 255 */ 256 public static final String SAE_CONFIG_SHARED_SECRET = "secret"; 257 258 /** 259 * SAE Config : data encryption algorithm. 260 * @supported.api 261 */ 262 public static final String SAE_CONFIG_DATA_ENCRYPTION_ALG = 263 "encryptionalgorithm"; 264 265 /** 266 * SAE Config : data encryption key strength. 267 * @supported.api 268 */ 269 public static final String SAE_CONFIG_ENCRYPTION_KEY_STRENGTH = 270 "encryptionkeystrength"; 271 272 /** 273 * SAE Config : Signature validity : since timetamp on signature. 274 * @supported.api 275 */ 276 public static final String SAE_CONFIG_SIG_VALIDITY_DURATION = 277 "saesigvalidityduration"; 278 /** 279 * Debug : true | false 280 */ 281 public static boolean dbg = false; 282 283 private Certs certs = null; 284 285 private static HashMap instances = new HashMap(); 286 private int tsDuration = 120000; // 2 minutes 287 private boolean asymsigning = false; 288 private boolean asymencryption = false; 289 private String dataEncAlg = "DES"; 290 private int encKeyStrength = 56; 291 292 /** 293 * Returns an instance to perform crypto operations. 294 * @param name 295 * @return <code>SecureAttrs</code> instance. 296 * @supported.api 297 */ 298 public static synchronized SecureAttrs getInstance(String name) 299 { 300 return (SecureAttrs)instances.get(name); 301 } 302 /** 303 * Initializes a SecureAttrs instance specified by <code>name</code>. 304 * If the instance already exists, it replaces it with the new instance. 305 * Use <code>SecureAttrs.getIstance(name)</code> to obtain the instance. 306 * @param name Name of the <code>SecureAttrs</code> instance. 307 * @param type Cryptographic key type. Possible values are 308 * <code>SecureAttrs.SAE_CRYPTO_TYPE_SYM<code>, and 309 * <code>SecureAttrs.SAE_CRYPTO_TYPE_ASYM</code> 310 * @param properties : please see SAE_CONFIG_* constants for configurable 311 * values. 312 * @throws Exception rethrows underlying exception. 313 * @supported.api 314 */ 315 synchronized public static void init( 316 String name, String type, Properties properties) throws Exception 317 { 318 SecureAttrs sa = new SecureAttrs(type, properties); 319 instances.put(name, sa); 320 } 321 322 /** 323 * Creates two instances of <code>SecureAttrs</code> named 324 * "symmetric" and "asymmetric" representing the two suppported 325 * crytp types. 326 * @param properties : please see SAE_CONFIG_* constants for configurable 327 * values. 328 * @throws Exception rethrows underlying exception. 329 * @supported.api 330 * @deprecated For backward compatability with older releases of this api. 331 * Replaced by {@link #init(String,String,Properties)} 332 */ 333 synchronized public static void init(Properties properties) throws Exception 334 { 335 init(SAE_CRYPTO_TYPE_ASYM, SAE_CRYPTO_TYPE_ASYM, properties); 336 init(SAE_CRYPTO_TYPE_SYM, SAE_CRYPTO_TYPE_SYM, properties); 337 } 338 339 /** 340 * Returns a Base64 encoded string comprising a signed set of attributes. 341 * 342 * @param attrs Attribute Value pairs to be processed. 343 * @param secret Shared secret (symmetric) Private key alias (asymmetric) 344 * 345 * @return Base64 encoded token String to be passed to a relying party. 346 * @supported.api 347 */ 348 public String getEncodedString(Map attrs, String secret) throws Exception 349 { 350 String signedAttrs = signAttributes(attrs, secret); 351 return Base64.encode(signedAttrs.getBytes("UTF-8")); 352 } 353 354 /** 355 * Returns encrypted string for the given attributes. The encrypted 356 * data is Base64 encoded string encrypted with supplied encryption 357 * secret and signs using shared secret. 358 * @param attrs Attribute Value pairs to be processed. 359 * @param secret Shared secret (symmetric) Private key alias (asymmetric) * @param encSecret The encryption secret (symmetric) or Public 360 * Key alias (asymmetric) 361 * @return Base64 encoded token String to be passed to a relying party. 362 * @supported.api 363 */ 364 public String getEncodedString(Map attrs, String secret, String encSecret) 365 throws Exception { 366 367 if(encSecret == null) { 368 return getEncodedString(attrs, secret); 369 } 370 371 String signedString = signAttributes(attrs, secret); 372 String encryptedString = null; 373 if(asymencryption) { 374 Key encKey = getPublicKey(encSecret).getPublicKey(); 375 encryptedString = DataEncryptor.encryptWithAsymmetricKey( 376 signedString, 377 dataEncAlg, 378 encKeyStrength, 379 encKey); 380 } else { 381 encryptedString = DataEncryptor.encryptWithSymmetricKey( 382 signedString, 383 dataEncAlg, 384 secret); 385 } 386 if(dbg) { 387 System.out.println("SAE.getEncodedString: encrypted string" + 388 encryptedString); 389 } 390 return encryptedString; 391 } 392 393 private String signAttributes(Map attrs, String secret) throws Exception { 394 if(attrs == null || attrs.isEmpty() ){ 395 return null; 396 } 397 398 StringBuffer sb = new StringBuffer(200); 399 Iterator iter = attrs.entrySet().iterator(); 400 while(iter.hasNext()) { 401 Map.Entry entry = (Map.Entry)iter.next(); 402 String key = (String)entry.getKey(); 403 String value = (String)entry.getValue(); 404 sb.append(key).append("=").append(value).append("|"); 405 } 406 407 sb.append("Signature=").append(getSignedString(attrs, secret)); 408 return sb.toString(); 409 } 410 411 /** 412 * Verifies a Base64 encoded string for authenticity based on the 413 * shared secret supplied. 414 * @param str Base64 encoded string containing attribute 415 * @param secret Shared secret (symmmetric) or Public Key (asymmetric) 416 * 417 * @return Decoded, verified and parsed attrbute name-valie pairs. 418 * @supported.api 419 */ 420 public Map verifyEncodedString(String str, String secret) throws Exception 421 { 422 if(str == null) { 423 return null; 424 } 425 426 Map map = getRawAttributesFromEncodedData(str); 427 if (dbg) 428 System.out.println("SAE:verifyEncodedString() : "+map); 429 String signatureValue = (String) map.remove("Signature"); 430 if(!verifyAttrs(map, signatureValue, secret)) { 431 return null; 432 } 433 return map; 434 } 435 436 /** 437 * Verifies the encrypted data string using encryption secret and 438 * shared secret that was used for signing. 439 * @param str Base64 encoded string containing attribute 440 * @param secret Shared secret (symmmetric) or Public Key (asymmetric) 441 * @param encSecret The encryption secret (symmetric) or Public 442 * Key alias (asymmetric) 443 * @return Decoded, verified and parsed attrbute name-valie pairs. 444 * @supported.api 445 */ 446 public Map verifyEncodedString(String str, String secret, String encSecret) 447 throws Exception { 448 449 if(encSecret == null) { 450 return verifyEncodedString(str, secret); 451 } 452 453 if(!isEncrypted(str)) { 454 return verifyEncodedString(str, secret); 455 } 456 if (str.indexOf(' ') > 0) { 457 str = str.replace(' ', '+'); 458 } 459 String decryptStr = null; 460 if(asymencryption) { 461 Key pKey = certs.getPrivateKey(encSecret); 462 decryptStr = DataEncryptor.decryptWithAsymmetricKey(str, 463 dataEncAlg, pKey); 464 } else { 465 decryptStr = DataEncryptor.decryptWithSymmetricKey(str, 466 dataEncAlg, encSecret); 467 } 468 if (dbg) { 469 System.out.println("SAE:verifyEncodedString() : "+ 470 "decrypted string " + decryptStr); 471 } 472 return verifyEncodedString(decryptStr, secret); 473 474 } 475 476 private boolean isEncrypted(String str) throws Exception { 477 478 if (str.indexOf(' ') > 0) { 479 str = str.replace(' ', '+'); 480 } 481 byte[] decoded = Base64.decode(str); 482 byte[] encString = new byte[9]; 483 for (int i=0; i < 9; i++) { 484 encString[i] = decoded[i]; 485 } 486 487 String tmp = new String(encString, "UTF-8"); 488 if(tmp.equals("ENCRYPTED")) { 489 return true; 490 } 491 return false; 492 } 493 494 /** 495 * Returns a decoded <code>Map</code> of attribute-value pairs. 496 * No verification is performed. Useful when retrieving data before 497 * verifying contents for authenticity. 498 * @param str Base64 encoded string containing attribute 499 * 500 * @return Decoded and parsed attrbute name-value pairs. 501 * @supported.api 502 */ 503 public Map getRawAttributesFromEncodedData(String str) throws Exception 504 { 505 if(str == null) { 506 return null; 507 } 508 509 if (str.indexOf(' ') > 0) 510 str = str.replace(' ', '+'); 511 byte[] bytes = Base64.decode(str); 512 String decoded = new String(bytes, "UTF-8"); 513 if(decoded.indexOf("|") == -1) { 514 return null; 515 } 516 StringTokenizer tokenizer = new StringTokenizer(decoded, "|"); 517 518 Map map = new HashMap(); 519 while(tokenizer.hasMoreTokens()) { 520 String st = tokenizer.nextToken(); 521 int index = st.indexOf("="); 522 if(index == -1) { 523 continue; 524 } 525 String attr = st.substring(0, index); 526 String value = st.substring(index+1, st.length()); 527 map.put(attr, value); 528 } 529 530 return map; 531 } 532 533 /** 534 * Returns a decoded <code>Map</code> of attribute-value pairs. 535 * No verification is performed. Useful when retrieving data before 536 * verifying contents for authenticity. 537 * @param str Base64 encoded string containing attribute 538 * @param encSecret The encryption secret (symmetric) or Public 539 * Key alias (asymmetric) 540 * @return Decoded and parsed attrbute name-value pairs. 541 * @supported.api 542 */ 543 public Map getRawAttributesFromEncodedData(String str, String encSecret) 544 throws Exception { 545 546 if(encSecret == null) { 547 return getRawAttributesFromEncodedData(str); 548 } 549 if (str.indexOf(' ') > 0) { 550 str = str.replace(' ', '+'); 551 } 552 if(!isEncrypted(str)) { 553 return getRawAttributesFromEncodedData(str); 554 } 555 String decryptStr = null; 556 if(asymencryption) { 557 Key pKey = certs.getPrivateKey(encSecret); 558 decryptStr = DataEncryptor.decryptWithAsymmetricKey(str, 559 dataEncAlg, pKey); 560 } else { 561 decryptStr = DataEncryptor.decryptWithSymmetricKey(str, 562 dataEncAlg, encSecret); 563 } 564 if(dbg) { 565 System.out.println("SAE.getRawAttributes() decrypted" + 566 " string" + decryptStr); 567 } 568 return getRawAttributesFromEncodedData(decryptStr); 569 } 570 571 /** 572 * This interface allows to set the private to be used for signing 573 * as an alternative to passing down <code>SAE_CONFIG_PRIVATE_KEY_ALIAS</a> 574 * via <code>init</code>. Use this interface if you do not want 575 * SecureAttr to obtain the signing key from a configured keystore. 576 * To use this key during signing, specify secret as null. 577 * @param privatekey 578 * @supported.api 579 */ 580 public void setPrivateKey(PrivateKey privatekey) 581 { 582 certs.setPrivatekey(privatekey); 583 } 584 585 /** 586 * This interface allows to register a public key to be used for signature 587 * verification. Use this interface if you do not want SecureAttrs to 588 * obtain public keys from a configured keystore. 589 * @param pubkeyalias 590 * @param x509certificate instance. 591 * @supported.api 592 */ 593 public void addPublicKey( 594 String pubkeyalias, X509Certificate x509certificate) 595 { 596 certs.addPublicKey(pubkeyalias, x509certificate); 597 } 598 599 private X509Certificate getPublicKey(String alias) 600 { 601 return certs.getPublicKey(alias); 602 } 603 604 /** 605 * Returns a String representing data in the attrs argument. 606 * The String generated can be one of the following depending 607 * on configuration : 608 * SHA1 digest based on a shared secret and current timestamp. 609 * or 610 * Digital signature based on a configured certificate key. 611 * 612 * @param attrs List of attribute Value pairs to be processed. 613 * @param secret Shared secret (symmmetric) or Private Key (asymmetric) 614 * 615 * @return token String to be passed to a relying party. 616 * @supported.api 617 */ 618 public String getSignedString(Map attrs, String secret) throws Exception 619 { 620 // Normalize 621 StringBuffer str = normalize(attrs); 622 // Setup a fresh timestamp 623 long timestamp = (new Date()).getTime(); 624 625 String signature = null; 626 627 if(asymsigning) 628 { 629 PrivateKey pKey = certs.getPrivateKey(secret); 630 signature = signAsym(str.append(timestamp).toString(), pKey); 631 } else 632 { 633 // Create seed : TIMESTAMP + shared secret 634 String seed = secret+timestamp; 635 // Encrypt 636 signature = encrypt(str+seed, seed); 637 } 638 if (signature == null) { 639 return null; 640 } 641 return ("TS"+timestamp + "TS"+signature); 642 } 643 644 /** 645 * Verifies the authenticity of data the attrs argument based 646 * on the token presented. Both attrs and token is sent by 647 * a asserting party. 648 * @param attrs List of attribute Value pairs to be processed. 649 * @param token token represnting attrs provided by asserting party. 650 * @param secret Shared secret (symmmetric) or Public Key (asymmetric) 651 * 652 * @return true if attrs and token verify okay, else returns false. 653 * @supported.api 654 */ 655 public boolean verifyAttrs(Map attrs, String token, String secret) 656 throws Exception 657 { 658 // Normalize 659 StringBuffer str = normalize(attrs); 660 // Retrieve timestamp 661 int idx = token.indexOf("TS", 2); 662 String ts = token.substring(2, idx); 663 long signts = Long.parseLong(ts); 664 long nowts = (new Date()).getTime(); 665 666 // Check timestamp validity 667 if ((nowts - signts) > tsDuration) 668 return false; 669 670 if(asymsigning) 671 { 672 String signature = token.substring(idx + 2, token.length()); 673 return verifyAsym(str.append(ts).toString(), 674 signature, getPublicKey(secret)); 675 } 676 // Create seed : TIMESTAMP + shared secret 677 String seed = secret + ts; 678 // Encrypt 679 String newstr ="TS"+ts+ "TS"+encrypt(str+seed, seed); 680 if (token.equals(newstr) ) 681 return true; 682 else 683 return false; 684 } 685 686 687 private SecureAttrs(String type, Properties properties) throws Exception 688 { 689 if (SAE_CRYPTO_TYPE_ASYM.equals(type)) { 690 asymsigning = true; 691 asymencryption = true; 692 } 693 String dur = properties.getProperty(SAE_CONFIG_SIG_VALIDITY_DURATION); 694 if (dur != null) 695 tsDuration = Integer.parseInt(dur); 696 697 String clzName = properties.getProperty(SAE_CONFIG_CERT_CLASS); 698 if (clzName != null) 699 certs = (Certs) Class.forName(clzName).newInstance(); 700 //"com.sun.identity.sae.api.FMCerts").newInstance(); 701 else 702 certs = new DefaultCerts(); 703 704 certs.init(properties); 705 dataEncAlg = (String)properties.get(SAE_CONFIG_DATA_ENCRYPTION_ALG); 706 String tmp = (String)properties.get( 707 SAE_CONFIG_ENCRYPTION_KEY_STRENGTH); 708 if(tmp != null) { 709 encKeyStrength = (new Integer(tmp)).intValue(); 710 } 711 } 712 713 private StringBuffer normalize(Map attrs) 714 { 715 // Sort the Map 716 TreeMap smap = new TreeMap(attrs); 717 718 // Flatten to a single String 719 StringBuffer str = new StringBuffer(); 720 Iterator iter = smap.keySet().iterator(); 721 while (iter.hasNext()) { 722 String key = (String) iter.next(); 723 str.append(key).append("=").append(smap.get(key)).append("|"); 724 } 725 return str; 726 } 727 728 private synchronized String encrypt(String plaintext, 729 String seed) throws Exception 730 { 731 MessageDigest md = null; 732 try 733 { 734 md = MessageDigest.getInstance("SHA"); //step 2 735 } catch(NoSuchAlgorithmException e) { 736 throw new Exception(e.getMessage()); 737 } 738 try 739 { 740 md.update((plaintext).getBytes("UTF-8")); //step 3 741 } catch(UnsupportedEncodingException e) { 742 throw new Exception(e.getMessage()); 743 } 744 745 byte raw[] = md.digest(); //step 4 746 String hash = Base64.encode(raw); 747 748 return hash; //step 6 749 } 750 private String signAsym(String s, PrivateKey privatekey) 751 { 752 if(s == null || s.length() == 0 || privatekey == null) { 753 if (dbg) 754 System.out.println("SAE : signAsym: returning since priv key null"); 755 return null; 756 } 757 String s1 = privatekey.getAlgorithm(); 758 Signature signature = null; 759 Object obj = null; 760 if(s1.equals("RSA")) 761 try 762 { 763 signature = Signature.getInstance("SHA1withRSA"); 764 String s2 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; 765 } 766 catch(Exception exception) 767 { 768 System.out.println("SAE:asym sign : RSA failed ="+exception); 769 return null; 770 } 771 else 772 if(s1.equals("DSA")) 773 { 774 try 775 { 776 signature = Signature.getInstance("SHA1withDSA"); 777 String s3 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; 778 } 779 catch(Exception exception1) 780 { 781 System.out.println("SAE:asym sign : DSA failed ="+exception1); 782 return null; 783 } 784 } else 785 { 786 System.out.println("SAE:asym sign : No Algorithm"); 787 return null; 788 } 789 try 790 { 791 signature.initSign(privatekey); 792 } 793 catch(Exception exception2) 794 { 795 System.out.println("SAE:asym sign : sig.initSign failed"+exception2); 796 return null; 797 } 798 try 799 { 800 System.out.println("Query str:"+s); 801 signature.update(s.getBytes()); 802 } 803 catch(Exception exception3) 804 { 805 System.out.println("SAE:asym sign : sig.update failed"+exception3); 806 return null; 807 } 808 byte abyte0[] = null; 809 try 810 { 811 abyte0 = signature.sign(); 812 } 813 catch(Exception exception4) 814 { 815 System.out.println("SAE:asym sign : sig.sign failed"+exception4); 816 return null; 817 } 818 if(abyte0 == null || abyte0.length == 0) 819 { 820 System.out.println("SAE:asym sign : sigBytes null"); 821 return null; 822 } else 823 { 824 String s4 = Base64.encode(abyte0); 825 System.out.println("B64 Signature="+s4); 826 return s4; 827 } 828 } 829 830 private boolean verifyAsym(String s, String s1, X509Certificate x509certificate) 831 { 832 if(s == null || s.length() == 0 || x509certificate == null || s1 == null) 833 { 834 if (dbg) 835 System.out.println("SAE:asym verify: qstring or cert or signature is null"); 836 return false; 837 } 838 byte abyte0[] = Base64.decode(s1); 839 if (dbg) 840 System.out.println("SAE:verifyAsym:signature="+abyte0+" origstr="+s1); 841 Object obj = null; 842 Object obj1 = null; 843 String s2 = x509certificate.getPublicKey().getAlgorithm(); 844 Signature signature = null; 845 if(s2.equals("DSA")) 846 try 847 { 848 signature = Signature.getInstance("SHA1withDSA"); 849 } 850 catch(Exception exception) 851 { 852 System.out.println("SAE:asym verify : DSA instance"+exception); 853 exception.printStackTrace(); 854 return false; 855 } 856 else 857 if(s2.equals("RSA")) 858 { 859 try 860 { 861 signature = Signature.getInstance("SHA1withRSA"); 862 } 863 catch(Exception exception1) 864 { 865 System.out.println("SAE:asym verify : RSA instance"+exception1); 866 exception1.printStackTrace(); 867 return false; 868 } 869 } else 870 { 871 System.out.println("SAE:asym verify : no instance"); 872 return false; 873 } 874 try 875 { 876 signature.initVerify(x509certificate); 877 } 878 catch(Exception exception2) 879 { 880 System.out.println("SAE:asym verify :sig.initVerify"+exception2); 881 exception2.printStackTrace(); 882 return false; 883 } 884 try 885 { 886 signature.update(s.getBytes()); 887 } 888 catch(Exception exception3) 889 { 890 System.out.println("SAE:asym verify :sig.update:"+exception3+" sig="+abyte0); 891 exception3.printStackTrace(); 892 return false; 893 } 894 boolean flag = false; 895 try 896 { 897 flag = signature.verify(abyte0); 898 } 899 catch(Exception exception4) 900 { 901 System.out.println("SAE:asym verify :sig.verify:"+exception4+"sig="+abyte0); 902 exception4.printStackTrace(); 903 return false; 904 } 905 return flag; 906 } 907 908 static public void main(String[] args) 909 { 910 try 911 { 912 SecureAttrs.dbg = true; 913 Properties properties = new Properties(); 914 properties.setProperty("keystorefile", "mykeystore"); 915 properties.setProperty("keystoretype", "JKS"); 916 properties.setProperty("keystorepass", "22222222"); 917 properties.setProperty("privatekeyalias", "test"); 918 properties.setProperty("publickeyalias", "test"); 919 properties.setProperty("privatekeypass", "22222222"); 920 properties.setProperty("encryptionkeystrength", "56"); 921 properties.setProperty("encryptionalgorithm", "DES"); 922 923 SecureAttrs.init("testsym", SecureAttrs.SAE_CRYPTO_TYPE_SYM, 924 properties); 925 SecureAttrs.init("testasym", SecureAttrs.SAE_CRYPTO_TYPE_ASYM, 926 properties); 927 System.out.println("TEST 1 START test encoded str ==========="); 928 SecureAttrs secureattrs = SecureAttrs.getInstance("testsym"); 929 String s = "YnJhbmNoPTAwNXxtYWlsPXVzZXI1QG1haWwuY29tfHN1bi51c2VyaWQ9dXNlcjV8U2lnbmF0dXJlPVRTMTE3NDI3ODY1OTM2NlRTbzI2MkhoL3R1dDRJc0U1V3ZqWjVSLzZkM0FzPQ=="; 930 Map map = secureattrs.verifyEncodedString(s, "secret"); 931 if(map == null) 932 System.out.println(" FAILED"); 933 else 934 System.out.println(" PASSED"+map); 935 System.out.println("TEST 1 END ================"); 936 System.out.println("TEST 2 START : encode followed by decode ==="); 937 HashMap hashmap = new HashMap(); 938 hashmap.put("branch", "bb"); 939 hashmap.put("mail", "mm"); 940 hashmap.put("sun.userid", "uu"); 941 hashmap.put("sun.spappurl", "apapp"); 942 System.out.println(" TEST 2a START : SYM KEY ==="); 943 secureattrs = SecureAttrs.getInstance("testsym"); 944 String s1 = "secret"; 945 String s2 = secureattrs.getEncodedString(hashmap, s1); 946 System.out.println("Encoded string: "+s2); 947 Map map1 = secureattrs.verifyEncodedString(s2, s1); 948 if(map1 != null) 949 System.out.println(" 2a PASSED "+map1); 950 else 951 System.out.println(" 2a FAILED "+map1); 952 System.out.println(" TEST 2b START : ASYM KEY ==="); 953 secureattrs = getInstance("testasym"); 954 s1 = "test"; 955 String s3 = secureattrs.getEncodedString(hashmap, s1); 956 System.out.println("Encoded string: "+s3); 957 map1 = secureattrs.verifyEncodedString(s3, s1); 958 if(map1 != null) 959 System.out.println(" 2b PASSED "+map1); 960 else 961 System.out.println(" 2b FAILED "+map1); 962 System.out.println("TEST 2 END ===================="); 963 System.out.println("TEST 3 START : decode with incorrect secret"); 964 System.out.println(" TEST 3a START : SYM KEY ==="); 965 secureattrs = getInstance("testsym"); 966 map1 = secureattrs.verifyEncodedString(s2, "junk"); 967 if(map1 != null) 968 System.out.println(" 3a FAILED "+map1); 969 else 970 System.out.println(" 3a PASSED "+map1); 971 System.out.println(" TEST 3b START : ASYM KEY ==="); 972 secureattrs = getInstance("testasym"); 973 map1 = secureattrs.verifyEncodedString(s3, "junk"); 974 if(map1 != null) 975 System.out.println(" 3b FAILED "+map1); 976 else 977 System.out.println(" 3b PASSED "+map1); 978 System.out.println("TEST 3 END ===================="); 979 System.out.println("TEST 4 START : decode with correct secret"); 980 System.out.println(" TEST 4a START : SYM KEY ==="); 981 secureattrs = getInstance("testsym"); 982 s1 = "secret"; 983 map1 = secureattrs.verifyEncodedString(s2, s1); 984 if(map1 != null) 985 System.out.println(" 4a PASSED "+map1); 986 else 987 System.out.println(" 4a FAILED "+map1); 988 System.out.println(" TEST 4b START : ASYM KEY ==="); 989 secureattrs = getInstance("testasym"); 990 s1 = "test"; 991 map1 = secureattrs.verifyEncodedString(s3, s1); 992 if(map1 != null) 993 System.out.println(" 4a PASSED "+map1); 994 else 995 System.out.println(" 4a FAILED "+map1); 996 System.out.println("TEST 4 END ===================="); 997 System.out.println(" TEST 5a START : ASYM KEY ==="); 998 secureattrs = getInstance("testasym"); 999 s1 = "test"; 1000 s3 = secureattrs.getEncodedString(hashmap, s1, s1); 1001 System.out.println("Encrypted string: "+s3); 1002 map1 = secureattrs.verifyEncodedString(s3, s1, s1); 1003 if(map1 != null) 1004 System.out.println(" 5a PASSED "+map1); 1005 else 1006 System.out.println(" 5a FAILED "+map1); 1007 System.out.println(" TEST 5b START : SYM KEY ==="); 1008 secureattrs = SecureAttrs.getInstance("testsym"); 1009 s1 = "secret"; 1010 s2 = secureattrs.getEncodedString(hashmap, s1, s1); 1011 System.out.println("Encrypted string: "+s2); 1012 map1 = secureattrs.verifyEncodedString(s2, s1, s1); 1013 if(map1 != null) 1014 System.out.println(" 5b PASSED "+map1); 1015 else 1016 System.out.println(" 5b FAILED "+map1); 1017 System.out.println("TEST 5 END ===================="); 1018 } 1019 catch(Exception exception) 1020 { 1021 exception.printStackTrace(); 1022 System.out.println("TEST Exc : "+exception); 1023 } 1024 1025 } 1026 public interface Certs { 1027 public void init(Properties props) throws Exception; 1028 public PrivateKey getPrivateKey(String alias); 1029 public X509Certificate getPublicKey(String alias); 1030 public void setPrivatekey(PrivateKey privatekey); 1031 public void addPublicKey( 1032 String pubkeyalias, X509Certificate x509certificate); 1033 } 1034 static class DefaultCerts implements Certs 1035 { 1036 private PrivateKey privateKey = null; 1037 private KeyStore ks = null; 1038 private String keystoreFile = ""; 1039 private HashMap keyTable = new HashMap(); 1040 private boolean cacheKeys = true; 1041 private String pkpass = null; 1042 1043 public void init(Properties properties) throws Exception 1044 { 1045 String keyfile = properties.getProperty("keystorefile"); 1046 if(keyfile != null) 1047 { 1048 String ktype = properties.getProperty( 1049 SAE_CONFIG_KEYSTORE_TYPE, "JKS"); 1050 ks = KeyStore.getInstance(ktype); 1051 FileInputStream fileinputstream = new FileInputStream(keyfile); 1052 String kpass = properties.getProperty(SAE_CONFIG_KEYSTORE_PASS); 1053 pkpass = properties.getProperty(SAE_CONFIG_PRIVATE_KEY_PASS); 1054 ks.load(fileinputstream, kpass.toCharArray()); 1055 String pkeyalias = properties.getProperty( 1056 SAE_CONFIG_PRIVATE_KEY_ALIAS ); 1057 if(pkeyalias != null) { 1058 privateKey = (PrivateKey)ks.getKey(pkeyalias, 1059 pkpass.toCharArray()); 1060 } 1061 String pubkeyalias = properties.getProperty( 1062 SAE_CONFIG_PUBLIC_KEY_ALIAS ); 1063 if ("false".equals(properties.getProperty( 1064 SAE_CONFIG_CACHE_KEYS))) 1065 cacheKeys = false; 1066 1067 if (cacheKeys && pubkeyalias != null) 1068 getPublicKeyFromKeystore(pubkeyalias); 1069 } 1070 } 1071 public PrivateKey getPrivateKey(String alias) 1072 { 1073 try { 1074 if (alias == null) 1075 return privateKey; 1076 return (PrivateKey)ks.getKey(alias, 1077 pkpass.toCharArray()); 1078 } catch (Exception ex) { 1079 return null; 1080 } 1081 } 1082 public X509Certificate getPublicKey(String alias) 1083 { 1084 X509Certificate x509certificate = 1085 (X509Certificate)keyTable.get(alias); 1086 if (x509certificate == null && ks != null) { 1087 try 1088 { 1089 x509certificate = getPublicKeyFromKeystore(alias); 1090 } 1091 catch(Exception exception) 1092 { 1093 System.out.println("SAE:getPublicKey:Exc:"+exception); 1094 } 1095 } 1096 return x509certificate; 1097 } 1098 public void setPrivatekey(PrivateKey privatekey) 1099 { 1100 privateKey = privatekey; 1101 } 1102 public void addPublicKey( 1103 String pubkeyalias, X509Certificate x509certificate) 1104 { 1105 keyTable.put(pubkeyalias, x509certificate); 1106 } 1107 private X509Certificate getPublicKeyFromKeystore(String pubkeyalias) 1108 throws Exception 1109 { 1110 X509Certificate x509certificate = 1111 (X509Certificate)ks.getCertificate(pubkeyalias); 1112 if(cacheKeys) 1113 keyTable.put(pubkeyalias, x509certificate); 1114 return x509certificate; 1115 } 1116 } 1117}
Copyright © 2010-2017, ForgeRock All Rights Reserved.