1 21 22 package org.apache.derby.client.am; 23 24 import java.security.Provider ; 25 import java.security.Security ; 26 import org.apache.derby.shared.common.reference.SQLState; 27 import org.apache.derby.shared.common.sanity.SanityManager; 28 29 42 public class EncryptionManager { 43 transient Agent agent_; 45 private static final byte modulusBytes__[] = { 47 (byte) 0xC6, (byte) 0x21, (byte) 0x12, (byte) 0xD7, 48 (byte) 0x3E, (byte) 0xE6, (byte) 0x13, (byte) 0xF0, 49 (byte) 0x94, (byte) 0x7A, (byte) 0xB3, (byte) 0x1F, 50 (byte) 0x0F, (byte) 0x68, (byte) 0x46, (byte) 0xA1, 51 (byte) 0xBF, (byte) 0xF5, (byte) 0xB3, (byte) 0xA4, 52 (byte) 0xCA, (byte) 0x0D, (byte) 0x60, (byte) 0xBC, 53 (byte) 0x1E, (byte) 0x4C, (byte) 0x7A, (byte) 0x0D, 54 (byte) 0x8C, (byte) 0x16, (byte) 0xB3, (byte) 0xE3 55 }; 56 57 private static final java.math.BigInteger modulus__ 60 = new java.math.BigInteger (1, modulusBytes__); 61 62 private static final byte baseBytes__[] = { 64 (byte) 0x46, (byte) 0x90, (byte) 0xFA, (byte) 0x1F, 65 (byte) 0x7B, (byte) 0x9E, (byte) 0x1D, (byte) 0x44, 66 (byte) 0x42, (byte) 0xC8, (byte) 0x6C, (byte) 0x91, 67 (byte) 0x14, (byte) 0x60, (byte) 0x3F, (byte) 0xDE, 68 (byte) 0xCF, (byte) 0x07, (byte) 0x1E, (byte) 0xDC, 69 (byte) 0xEC, (byte) 0x5F, (byte) 0x62, (byte) 0x6E, 70 (byte) 0x21, (byte) 0xE2, (byte) 0x56, (byte) 0xAE, 71 (byte) 0xD9, (byte) 0xEA, (byte) 0x34, (byte) 0xE4 72 }; 73 74 private static final java.math.BigInteger base__ = 76 new java.math.BigInteger (1, baseBytes__); 77 78 private static final int exponential_length__ = 255; 80 81 private javax.crypto.spec.DHParameterSpec paramSpec_; 82 private java.security.KeyPairGenerator keyPairGenerator_; 83 private java.security.KeyPair keyPair_; 84 private javax.crypto.KeyAgreement keyAgreement_; 85 86 private byte[] token_; private byte[] secKey_; private javax.crypto.SecretKeyFactory secretKeyFactory_ = null; 89 private String providerName; private Provider provider; 91 92 private java.security.MessageDigest messageDigest = null; 97 private java.security.SecureRandom secureRandom = null; 98 private final static int SECMEC_USRSSBPWD_SEED_LEN = 8; private static final byte SECMEC_USRSSBPWD_PWDSEQS[] = { 101 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 102 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01 103 }; 104 private final static String SHA_1_PRNG_ALGORITHM = "SHA1PRNG"; 106 public final static String SHA_1_DIGEST_ALGORITHM = "SHA-1"; 107 108 public EncryptionManager(Agent agent) throws SqlException { 111 agent_ = agent; 112 try { 113 Provider [] list = Security.getProviders("KeyAgreement.DH"); 115 if (list == null) { 116 throw new java.security.NoSuchProviderException (); 117 } 118 provider = list[0]; 119 providerName = provider.getName(); 120 paramSpec_ = new javax.crypto.spec.DHParameterSpec(modulus__, base__, exponential_length__); 121 keyPairGenerator_ = java.security.KeyPairGenerator.getInstance("DH", providerName); 122 keyPairGenerator_.initialize(paramSpec_); 123 keyPair_ = keyPairGenerator_.generateKeyPair(); 124 keyAgreement_ = javax.crypto.KeyAgreement.getInstance("DH", providerName); 125 keyAgreement_.init(keyPair_.getPrivate()); 126 } catch (java.security.GeneralSecurityException e) { 127 throw new SqlException(agent_.logWriter_, 128 new ClientMessageId(SQLState.SECURITY_EXCEPTION_ENCOUNTERED), e); 129 } 130 } 131 132 public EncryptionManager(Agent agent, String algorithm) throws SqlException { 140 agent_ = agent; 141 try { 142 messageDigest = java.security.MessageDigest.getInstance(algorithm); 146 secureRandom = 149 java.security.SecureRandom.getInstance(SHA_1_PRNG_ALGORITHM); 150 } catch (java.security.NoSuchAlgorithmException nsae) { 151 throw new SqlException(agent_.logWriter_, 157 new ClientMessageId(SQLState.SECURITY_EXCEPTION_ENCOUNTERED), 158 nsae); 159 } 160 } 161 162 public byte[] obtainPublicKey() { 170 171 java.math.BigInteger aPub = ((javax.crypto.interfaces.DHPublicKey) keyPair_.getPublic()).getY(); 174 byte[] aPubKey = aPub.toByteArray(); 175 176 if (aPubKey.length == 33 && aPubKey[0] == 0) { 184 byte[] newKey = new byte[32]; 186 for (int i = 0; i < newKey.length; i++) { 187 newKey[i] = aPubKey[i + 1]; 188 } 189 return newKey; 190 } 191 192 if (aPubKey.length < 32) { 197 byte[] newKey = new byte[32]; 198 int i; 199 for (i = 0; i < 32 - aPubKey.length; i++) { 200 newKey[i] = 0; 201 } 202 for (int j = i; j < newKey.length; j++) { 203 newKey[j] = aPubKey[j - i]; 204 } 205 return newKey; 206 } 207 return aPubKey; 208 } 209 210 private byte[] calculateEncryptionToken(int securityMechanism, byte[] initVector) { 221 byte[] token = new byte[8]; 222 223 if (securityMechanism == 7) { 225 if (initVector.length < 8) { for (int i = 0; i < initVector.length; i++) { 227 token[i] = initVector[i]; 228 } 229 for (int i = initVector.length; i < 8; i++) { 230 token[i] = 0; 231 } 232 } else { for (int i = 0; i < 8; i++) { 234 token[i] = initVector[i]; 235 } 236 } 237 } 238 else if (securityMechanism == 9) { 241 for (int i = 0; i < 8; i++) { 242 token[i] = initVector[i + 12]; 243 } 244 } 245 return token; 246 } 247 248 private void keyParityCheck(byte[] key) throws SqlException { 253 byte temp; 254 int changeParity; 255 if (key.length != 8) { 256 throw new SqlException(agent_.logWriter_, 257 new ClientMessageId(SQLState.DES_KEY_HAS_WRONG_LENGTH), 258 new Integer (8), new Integer (key.length)); 259 260 } 261 for (int i = 0; i < 8; i++) { 262 temp = key[i]; 263 changeParity = 1; 264 for (int j = 0; j < 8; j++) { 265 if (temp < 0) { 266 changeParity = 1 - changeParity; 267 } 268 temp = (byte) (temp << 1); 269 } 270 if (changeParity == 1) { 271 if ((key[i] & 1) != 0) { 272 key[i] &= 0xfe; 273 } else { 274 key[i] |= 1; 275 } 276 } 277 } 278 } 279 280 private byte[] generatePrivateKey(byte[] targetPublicKey) throws SqlException { 283 try { 284 285 java.security.KeyFactory keyFac = java.security.KeyFactory.getInstance("DH", provider); 287 288 java.math.BigInteger publicKey = new java.math.BigInteger (1, targetPublicKey); 291 javax.crypto.spec.DHPublicKeySpec dhKeySpec = 292 new javax.crypto.spec.DHPublicKeySpec(publicKey, modulus__, base__); 293 java.security.PublicKey pubKey = keyFac.generatePublic(dhKeySpec); 294 295 keyAgreement_.doPhase(pubKey, true); 297 298 byte[] sharedSecret = keyAgreement_.generateSecret(); 302 byte[] newKey = new byte[32]; 303 304 if (sharedSecret.length == 33 && sharedSecret[0] == 0) { 308 for (int i = 0; i < newKey.length; i++) { 309 newKey[i] = sharedSecret[i + 1]; 310 } 311 312 } 313 if (sharedSecret.length < 32) { 314 int i; 315 for (i = 0; i < (32 - sharedSecret.length); i++) { 316 newKey[i] = 0; 317 } 318 for (int j = i; j < sharedSecret.length; j++) { 319 newKey[j] = sharedSecret[j - i]; 320 } 321 } 322 323 byte[] key = new byte[8]; 331 332 if (sharedSecret.length == 32) { 334 for (int i = 0; i < 8; i++) { 335 key[i] = sharedSecret[i + 12]; 336 } 337 } else if (sharedSecret.length == 33 || sharedSecret.length < 32) { 338 for (int i = 0; i < 8; i++) { 339 key[i] = newKey[i + 12]; 340 } 341 } else { 342 throw new SqlException(agent_.logWriter_, 343 new ClientMessageId(SQLState.SHARED_KEY_LENGTH_ERROR), 344 new Integer (sharedSecret.length)); 345 } 346 347 keyParityCheck(key); 349 return key; 350 } 351 catch (java.security.GeneralSecurityException e) { 352 throw new SqlException(agent_.logWriter_, 353 new ClientMessageId(SQLState.SECURITY_EXCEPTION_ENCOUNTERED), e); 354 } 355 } 356 357 public byte[] encryptData(byte[] plainText, 366 int securityMechanism, 367 byte[] initVector, 368 byte[] targetPublicKey) throws SqlException { 369 370 byte[] cipherText = null; 371 java.security.Key key = null; 372 373 if (token_ == null) { 374 token_ = calculateEncryptionToken(securityMechanism, initVector); 375 } 376 377 try { 378 if (secKey_ == null) { 379 secKey_ = generatePrivateKey(targetPublicKey); 381 javax.crypto.spec.SecretKeySpec desKey = new javax.crypto.spec.SecretKeySpec(secKey_, "DES"); 382 key = desKey; 383 } else { 384 javax.crypto.spec.DESKeySpec desKey = new javax.crypto.spec.DESKeySpec(secKey_); 386 if (secretKeyFactory_ == null) { 387 secretKeyFactory_ = javax.crypto.SecretKeyFactory.getInstance("DES", providerName); 388 } 389 key = secretKeyFactory_.generateSecret(desKey); 390 } 391 392 javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("DES/CBC/PKCS5Padding", providerName); 398 399 javax.crypto.spec.IvParameterSpec ivParam = new javax.crypto.spec.IvParameterSpec(token_); 402 403 cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key, ivParam); 406 407 cipherText = cipher.doFinal(plainText); 409 } catch (javax.crypto.NoSuchPaddingException e) { 410 throw new SqlException(agent_.logWriter_, 411 new ClientMessageId(SQLState.CRYPTO_NO_SUCH_PADDING)); 412 } catch (javax.crypto.BadPaddingException e) { 413 throw new SqlException(agent_.logWriter_, 414 new ClientMessageId(SQLState.CRYPTO_BAD_PADDING)); 415 } catch (javax.crypto.IllegalBlockSizeException e) { 416 throw new SqlException(agent_.logWriter_, 417 new ClientMessageId(SQLState.CRYPTO_ILLEGAL_BLOCK_SIZE)); 418 } catch (java.security.GeneralSecurityException e) { 419 throw new SqlException(agent_.logWriter_, 420 new ClientMessageId(SQLState.SECURITY_EXCEPTION_ENCOUNTERED), e); 421 } 422 423 return cipherText; 424 } 425 426 427 public byte[] decryptData(byte[] cipherText, 436 int securityMechanism, 437 byte[] initVector, 438 byte[] targetPublicKey) throws SqlException { 439 440 byte[] plainText = null; 441 java.security.Key key = null; 442 443 if (token_ == null) { 444 token_ = calculateEncryptionToken(securityMechanism, initVector); 445 } 446 447 try { 448 if (secKey_ == null) { 449 secKey_ = generatePrivateKey(targetPublicKey); 451 javax.crypto.spec.SecretKeySpec desKey = new javax.crypto.spec.SecretKeySpec(secKey_, "DES"); 452 key = desKey; 453 } else { 454 javax.crypto.spec.DESKeySpec desKey = new javax.crypto.spec.DESKeySpec(secKey_); 456 if (secretKeyFactory_ == null) { 457 secretKeyFactory_ = javax.crypto.SecretKeyFactory.getInstance("DES", providerName); 458 } 459 key = secretKeyFactory_.generateSecret(desKey); 460 } 461 462 javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("DES/CBC/PKCS5Padding", providerName); 468 469 javax.crypto.spec.IvParameterSpec ivParam = new javax.crypto.spec.IvParameterSpec(token_); 472 473 cipher.init(javax.crypto.Cipher.DECRYPT_MODE, key, ivParam); 476 477 plainText = cipher.doFinal(cipherText); 479 } catch (javax.crypto.NoSuchPaddingException e) { 480 throw new SqlException(agent_.logWriter_, 481 new ClientMessageId(SQLState.CRYPTO_NO_SUCH_PADDING)); 482 } catch (javax.crypto.BadPaddingException e) { 483 throw new SqlException(agent_.logWriter_, 484 new ClientMessageId(SQLState.CRYPTO_BAD_PADDING)); 485 } catch (javax.crypto.IllegalBlockSizeException e) { 486 throw new SqlException(agent_.logWriter_, 487 new ClientMessageId(SQLState.CRYPTO_ILLEGAL_BLOCK_SIZE)); 488 } catch (java.security.GeneralSecurityException e) { 489 throw new SqlException(agent_.logWriter_, 490 new ClientMessageId(SQLState.SECURITY_EXCEPTION_ENCOUNTERED), e); 491 } 492 return plainText; 493 } 494 495 public void setInitVector(byte[] initVector) { 496 token_ = initVector; 497 } 498 499 public void setSecKey(byte[] secKey) { 500 secKey_ = secKey; 501 } 502 503 public void resetSecurityKeys() { 504 token_ = null; 505 secKey_ = null; 506 } 507 508 511 512 517 public byte[] generateSeed() { 518 byte randomSeedBytes[] = new byte[SECMEC_USRSSBPWD_SEED_LEN]; 519 secureRandom.setSeed(secureRandom.generateSeed( 520 SECMEC_USRSSBPWD_SEED_LEN)); 521 secureRandom.nextBytes(randomSeedBytes); 522 return randomSeedBytes; 523 } 524 525 551 public byte[] substitutePassword( 552 String userName, 553 String password, 554 byte[] sourceSeed_, 555 byte[] targetSeed_) throws SqlException { 556 557 String ID_PATTERN_NEW_SCHEME = "3b60"; 559 560 byte[] passwordSubstitute; 562 563 if (SanityManager.DEBUG) { 565 SanityManager.ASSERT((messageDigest != null) && 566 (SHA_1_DIGEST_ALGORITHM.equals( 567 messageDigest.getAlgorithm()))); 568 } 569 570 messageDigest.reset(); 591 592 messageDigest.update(this.toHexByte(password, 0, password.length())); 593 byte[] encryptVal = messageDigest.digest(); 594 String hexString = ID_PATTERN_NEW_SCHEME + 595 this.toHexString(encryptVal, 0, encryptVal.length); 596 597 byte[] userBytes = this.toHexByte(userName, 0, userName.length()); 599 messageDigest.update(userBytes); 600 messageDigest.update(this.toHexByte(hexString, 0, hexString.length())); 601 byte[] passwordToken = messageDigest.digest(); 602 603 messageDigest.update(passwordToken); 605 messageDigest.update(targetSeed_); 606 messageDigest.update(sourceSeed_); 607 messageDigest.update(userBytes); 608 messageDigest.update(SECMEC_USRSSBPWD_PWDSEQS); 609 610 passwordSubstitute = messageDigest.digest(); 611 612 return passwordSubstitute; 613 } 614 615 620 621 private static char[] hex_table = { 622 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 623 'a', 'b', 'c', 'd', 'e', 'f' 624 }; 625 626 643 private String toHexString(byte[] data, int offset, int length) 644 { 645 StringBuffer s = new StringBuffer (length*2); 646 int end = offset+length; 647 648 for (int i = offset; i < end; i++) 649 { 650 int high_nibble = (data[i] & 0xf0) >>> 4; 651 int low_nibble = (data[i] & 0x0f); 652 s.append(hex_table[high_nibble]); 653 s.append(hex_table[low_nibble]); 654 } 655 656 return s.toString(); 657 } 658 659 676 private byte[] toHexByte(String str, int offset, int length) 677 { 678 byte[] data = new byte[(length - offset) * 2]; 679 int end = offset+length; 680 681 for (int i = offset; i < end; i++) 682 { 683 char ch = str.charAt(i); 684 int high_nibble = (ch & 0xf0) >>> 4; 685 int low_nibble = (ch & 0x0f); 686 data[i] = (byte)high_nibble; 687 data[i+1] = (byte)low_nibble; 688 } 689 return data; 690 } 691 } 692 | Popular Tags |