| 1 21 22 package net.sourceforge.jcetaglib.lib; 23 24 import net.sourceforge.jcetaglib.exceptions.CryptoException; 25 import net.sourceforge.jcetaglib.exceptions.HeaderException; 26 import net.sourceforge.jcetaglib.exceptions.InvalidHMACException; 27 import net.sourceforge.jcetaglib.exceptions.InvalidSignatureException; 28 import net.sourceforge.jcetaglib.tools.*; 29 import org.bouncycastle.jce.provider.BouncyCastleProvider; 30 import org.bouncycastle.util.encoders.Base64; 31 32 import javax.crypto.Cipher; 33 import javax.crypto.KeyGenerator; 34 import javax.crypto.Mac; 35 import javax.crypto.SecretKey; 36 import javax.crypto.spec.IvParameterSpec; 37 import javax.crypto.spec.SecretKeySpec; 38 import java.io.*; 39 import java.security.*; 40 import java.security.cert.CertificateFactory ; 41 import java.security.cert.X509Certificate ; 42 43 51 public class Hybrid { 52 private static int BUFFERSIZE_TEXT = 1204; 54 private static int BUFFERSIZE_FILE = 8192; 55 56 static final int FILE_HEADER = 0x7e01; static final int DATA_BLOCK = 1; static final int FINAL_DATA_BLOCK = 2; static final int HMAC_BLOCK = 3; static final int SIG_BLOCK = 3; static final int CERT_BLOCK = 4; static final int KEY_BLOCK = 16; static final int IV_BLOCK = 17; static final int LOCK_BLOCK = 18; static final int HMAC_KEY_BLOCK = 18; 66 67 80 public static StringBuffer encryptWithHMAC(StringBuffer text 81 , PublicKey receiverKey 82 , String algorithm 83 , byte[] seed 84 , int strength 85 , String mode 86 , String padding) throws CryptoException { 87 88 ByteArrayOutputStream bao = null; 89 DataOutputStream dao = null; 90 91 try { 92 bao = new ByteArrayOutputStream(); 93 dao = new DataOutputStream(bao); 94 95 encryptWithHMAC(new ByteArrayInputStream(text.toString().getBytes()), dao, receiverKey, algorithm, seed, strength, mode, padding, BUFFERSIZE_TEXT); 97 return new StringBuffer (new String (Base64.encode(bao.toByteArray()))); 98 } catch (IOException ioe) { 99 ioe.printStackTrace(); 100 throw new CryptoException(ioe.getMessage()); 101 } finally { 102 if (dao != null) { 103 try { 105 dao.close(); 106 } catch (IOException e) { 107 ; 108 } 109 } 110 } 111 } 112 113 127 public static void encryptFileWithHMAC(String file 128 , String newfile 129 , PublicKey receiverKey 130 , String algorithm 131 , byte[] seed 132 , int strength 133 , String mode 134 , String padding) throws CryptoException, IOException { 135 136 FileInputStream fis = null; 137 FileOutputStream fos = null; 138 DataOutputStream dao = null; 139 140 try { 141 fis = new FileInputStream(file); 142 143 fos = new FileOutputStream(newfile); 144 dao = new DataOutputStream(fos); 145 146 encryptWithHMAC(fis, dao, receiverKey, algorithm, seed, strength, mode, padding, BUFFERSIZE_FILE); 148 149 } catch (IOException ioe) { 150 ioe.printStackTrace(); 151 throw new IOException(ioe.getMessage()); 152 } finally { 153 if (dao != null) { 154 try { 156 dao.close(); 157 } catch (IOException e) { 158 ; 159 } 160 } 161 if (fis != null) { 162 try { 164 fis.close(); 165 } catch (IOException e) { 166 ; 167 } 168 } 169 } 170 } 171 172 187 public static void encryptWithHMAC(InputStream is 188 , DataOutputStream daos 189 , PublicKey receiverKey 190 , String algorithm 191 , byte[] seed 192 , int strength 193 , String mode 194 , String padding 195 , int bufferlength) 196 throws CryptoException, IOException { 197 198 MacOutputStream macStr = null; 199 DataOutputStream dataStr = null; 200 201 try { 202 Security.addProvider(new BouncyCastleProvider()); 203 204 SecureRandom secRand = Seed.getSecureRandom(seed); 205 206 KeyGenerator keyGen = KeyGenerator.getInstance(algorithm, "BC"); 208 keyGen.init(strength, secRand); 209 Key symKey = keyGen.generateKey(); 210 211 Cipher outputCipher = Cipher.getInstance(algorithm + "/" + mode + "/" + padding, "BC"); 213 outputCipher.init(Cipher.ENCRYPT_MODE, symKey, secRand); 214 215 byte[] keyEnc = symKey.getEncoded(); 218 byte[] keyIV = outputCipher.getIV(); 219 220 Mac mac = Mac.getInstance("HMACSHA1", "BC"); 222 223 byte[] macKeyBytes = new byte[20]; secRand.nextBytes(macKeyBytes); 226 Key macKey = new SecretKeySpec(macKeyBytes, "HMACSHA1"); 227 mac.init(macKey); 229 Cipher rsaEng = Cipher.getInstance("RSA/None/OAEPPadding", "BC"); 231 rsaEng.init(Cipher.ENCRYPT_MODE, receiverKey, secRand); 232 233 macStr = new MacOutputStream(daos, mac); 235 dataStr = new DataOutputStream(macStr); 236 237 dataStr.writeShort(FILE_HEADER); 240 dataStr.writeShort(KEY_BLOCK); byte[] tmp = rsaEng.doFinal(keyEnc); dataStr.writeInt(tmp.length); dataStr.write(tmp); Clean.blank(tmp); 247 dataStr.writeShort(IV_BLOCK); tmp = rsaEng.doFinal(keyIV); dataStr.writeInt(tmp.length); dataStr.write(tmp); Clean.blank(tmp); 254 dataStr.writeShort(HMAC_KEY_BLOCK); tmp = outputCipher.doFinal(macKey.getEncoded()); dataStr.writeInt(tmp.length); dataStr.write(tmp); Clean.blank(tmp); 261 264 int l = 0; byte[] buf = new byte[bufferlength]; byte[] out = null; 269 while ((l = is.read(buf)) > -1) { 271 out = outputCipher.update(buf, 0, l); if (out != null) { 273 dataStr.writeShort(DATA_BLOCK); dataStr.writeInt(out.length); dataStr.write(out); } 277 } 278 279 out = outputCipher.doFinal(); dataStr.writeShort(FINAL_DATA_BLOCK); dataStr.writeInt(out.length); dataStr.write(out); 285 Clean.blank(buf); buf = null; 288 dataStr.writeShort(HMAC_BLOCK); dataStr.flush(); 292 tmp = mac.doFinal(); dataStr.writeInt(tmp.length); dataStr.write(tmp); Clean.blank(tmp); } catch (IOException ioe) { 297 ioe.printStackTrace(); 298 throw new IOException(ioe.getMessage()); 299 } catch (Exception ex) { 300 ex.printStackTrace(); 301 throw new CryptoException(ex.getMessage()); 302 } finally { 303 if (dataStr != null) { 304 try { 305 dataStr.close(); 306 } catch (IOException ioe) { 307 ; 308 } 309 } 310 } 311 } 312 313 326 public static StringBuffer decryptAndVerifyHMAC(StringBuffer text 327 , PrivateKey privKey 328 , String algorithm 329 , String mode 330 , String padding) throws HeaderException, InvalidHMACException, CryptoException { 331 332 ByteArrayOutputStream bao = null; 333 DataOutputStream dao = null; 334 335 try { 336 bao = new ByteArrayOutputStream(); 337 dao = new DataOutputStream(bao); 338 339 decryptAndVerifyHMAC(new ByteArrayInputStream(Base64.decode(text.toString())), dao, privKey, algorithm, mode, padding, BUFFERSIZE_TEXT); 341 342 return new StringBuffer (new String (bao.toByteArray())); 343 } catch (HeaderException he) { 344 throw new HeaderException(he.getMessage()); 345 } catch (InvalidHMACException ihe) { 346 throw new InvalidHMACException(ihe.getMessage()); 347 } catch (Exception ioe) { 348 ioe.printStackTrace(); 349 throw new CryptoException(ioe.getMessage()); 350 } finally { 351 if (dao != null) { 352 try { 354 dao.close(); 355 } catch (IOException e) { 356 ; 357 } 358 } 359 } 360 } 361 362 376 public static void decryptFileAndVerifyHMAC(String file 377 , String newfile 378 , PrivateKey privKey 379 , String algorithm 380 , String mode 381 , String padding) throws CryptoException, HeaderException, InvalidHMACException, IOException { 382 383 SecureRandom secRand; 384 Mac mac = null; 385 Cipher cipher = null; 386 Cipher decHMAC = null; 387 388 SecretKey symKey = null; SecretKey macKey = null; 391 byte[] keyIV = null; byte[] macCode = null; 394 DataInputStream dataIn = null; 395 MacInputStream macStr = null; 396 DataInputStream dataStr = null; 397 398 FileOutputStream outStr = null; 399 400 try { 401 Security.addProvider(new BouncyCastleProvider()); 402 403 secRand = SecureRandom.getInstance("SHA1PRNG", "SUN"); 404 405 dataIn = new DataInputStream(new FileInputStream(file)); 406 407 int l = 0; boolean ena = false; boolean stop = false; 411 Cipher rsaEng = Cipher.getInstance("RSA/None/OAEPPadding", "BC"); 413 rsaEng.init(Cipher.DECRYPT_MODE, privKey, secRand); 415 while (!stop) { 416 try { 417 int cmd = dataIn.readShort(); 419 if (cmd == FILE_HEADER) { 421 ena = true; continue; 423 } 424 425 if (cmd == DATA_BLOCK) { 427 if (!ena) { 428 throw new HeaderException("Broken header"); 429 } 430 431 l = dataIn.readInt(); dataIn.skip(l); continue; 434 } 435 436 if (cmd == FINAL_DATA_BLOCK) { 438 if (!ena) { 439 throw new HeaderException("Broken header"); 440 } 441 l = dataIn.readInt(); dataIn.skip(l); continue; 444 } 445 446 if (cmd == HMAC_BLOCK) { 448 if (!ena) { 449 throw new HeaderException("Broken header"); 450 } 451 l = dataIn.readInt(); macCode = new byte[l]; dataIn.readFully(macCode); continue; 455 } 456 457 if (cmd == KEY_BLOCK) { 459 if (!ena) { 460 throw new HeaderException("Broken header"); 461 } 462 463 l = dataIn.readInt(); byte[] d = new byte[l]; dataIn.readFully(d); 467 471 symKey = new SecretKeySpec(rsaEng.doFinal(d), algorithm); 472 continue; 473 } 474 475 if (cmd == IV_BLOCK) { 477 if (!ena) { 478 throw new HeaderException("Broken header"); 479 } 480 l = dataIn.readInt(); keyIV = new byte[l]; dataIn.readFully(keyIV); keyIV = rsaEng.doFinal(keyIV); continue; 485 } 486 487 if (cmd == HMAC_KEY_BLOCK) { 489 if (!ena) { 490 throw new HeaderException("Broken header"); 491 } 492 493 decHMAC = Cipher.getInstance(algorithm + "/" + mode + "/" + padding, "BC"); 495 decHMAC.init(Cipher.DECRYPT_MODE, symKey, new IvParameterSpec(keyIV)); 496 l = dataIn.readInt(); byte[] d = new byte[l]; dataIn.readFully(d); macKey = new SecretKeySpec(decHMAC.doFinal(d), "HMACSHA1"); 501 continue; 502 } 503 } catch (EOFException eof) { 504 stop = true; 505 } 506 } 507 508 mac = Mac.getInstance("HMACSHA1", "BC"); mac.init(macKey); 511 macStr = new MacInputStream(new FileInputStream(file), mac); 513 dataStr = new DataInputStream(macStr); 514 515 int cmd = 0; byte[] buf = new byte[BUFFERSIZE_FILE]; l = 0; 519 do { 520 cmd = dataStr.readShort(); 522 if (cmd == DATA_BLOCK) { 524 l = dataStr.readInt(); dataStr.read(buf, 0, l); } 527 528 if (cmd == FINAL_DATA_BLOCK) { 530 l = dataStr.readInt(); 531 dataStr.read(buf, 0, l); } 533 534 535 if (cmd == KEY_BLOCK) { 537 l = dataStr.readInt(); 538 dataStr.read(buf, 0, l); } 540 541 if (cmd == IV_BLOCK) { 543 l = dataStr.readInt(); 544 dataStr.read(buf, 0, l); } 546 547 if (cmd == HMAC_KEY_BLOCK) { 549 l = dataStr.readInt(); 550 dataStr.read(buf, 0, l); } 552 } while (cmd != HMAC_BLOCK); 553 554 buf = mac.doFinal(); 555 dataStr.close(); 556 557 if (!MessageDigest.isEqual(buf, macCode)) { 558 throw new InvalidHMACException("Invalid HMAC"); 559 } 560 561 cipher = Cipher.getInstance(algorithm + "/" + mode + "/" + padding, "BC"); 562 cipher.init(Cipher.DECRYPT_MODE, symKey, new IvParameterSpec(keyIV)); 563 564 outStr = new FileOutputStream(newfile); 566 dataStr = new DataInputStream(new FileInputStream(file)); 568 569 stop = false; cmd = 0; l = 0; buf = new byte[BUFFERSIZE_FILE]; byte[] out = null; 575 for (; ;) { 576 cmd = dataStr.readShort(); 578 if (cmd == DATA_BLOCK) { 579 l = dataStr.readInt(); dataStr.readFully(buf, 0, l); out = cipher.update(buf, 0, l); 582 if (out != null) outStr.write(out); 583 } 584 585 if (cmd == FINAL_DATA_BLOCK) { 586 l = dataStr.readInt(); dataStr.readFully(buf, 0, l); out = cipher.doFinal(buf, 0, l); 589 if (out != null) outStr.write(out); 590 break; 591 } 592 593 if (cmd == KEY_BLOCK) { 596 l = dataStr.readInt(); 597 dataStr.skip(l); 598 } 599 600 if (cmd == IV_BLOCK) { 602 l = dataStr.readInt(); 603 dataStr.skip(l); 604 } 605 606 if (cmd == HMAC_BLOCK) { 608 l = dataStr.readInt(); 609 dataStr.skip(l); 610 } 611 612 if (cmd == HMAC_KEY_BLOCK) { 614 l = dataStr.readInt(); 615 dataStr.skip(l); 616 } 617 } 618 } catch (IOException ioe) { 619 ioe.printStackTrace(); 620 throw new IOException(ioe.getMessage()); 621 } catch (HeaderException he) { 622 he.printStackTrace(); 623 throw new HeaderException(he.getMessage()); 624 } catch (InvalidHMACException ihe) { 625 ihe.printStackTrace(); 626 throw new InvalidHMACException(ihe.getMessage()); 627 } catch (Exception ex) { 628 ex.printStackTrace(); 629 throw new CryptoException(ex.getMessage()); 630 } finally { 631 if (outStr != null) { 632 try { 634 outStr.close(); 635 } catch (IOException e) { 636 ; 637 } 638 } 639 if (dataStr != null) { 640 try { 642 dataStr.close(); 643 } catch (IOException e) { 644 ; 645 } 646 } 647 } 648 } 649 650 665 public static void decryptAndVerifyHMAC(InputStream is 666 , DataOutputStream daos 667 , PrivateKey privKey 668 , String algorithm 669 , String mode 670 , String padding 671 , int bufferlength) 672 throws IOException, HeaderException, InvalidHMACException, CryptoException { 673 674 SecureRandom secRand; 675 Mac mac = null; 676 Cipher cipher = null; 677 Cipher decHMAC = null; 678 679 SecretKey symKey = null; SecretKey macKey = null; 682 byte[] keyIV = null; byte[] macCode = null; 685 DataInputStream dataIn = null; 686 MacInputStream macStr = null; 687 DataInputStream dataStr = null; 688 689 try { 690 Security.addProvider(new BouncyCastleProvider()); 691 692 secRand = SecureRandom.getInstance("SHA1PRNG", "SUN"); 693 694 dataIn = new DataInputStream(is); 695 696 int l = 0; boolean ena = false; boolean stop = false; 700 Cipher rsaEng = Cipher.getInstance("RSA/None/OAEPPadding", "BC"); 702 rsaEng.init(Cipher.DECRYPT_MODE, privKey, secRand); 704 while (!stop) { 705 try { 706 int cmd = dataIn.readShort(); 708 if (cmd == FILE_HEADER) { 710 ena = true; continue; 712 } 713 714 if (cmd == DATA_BLOCK) { 716 if (!ena) { 717 throw new HeaderException("Broken header"); 718 } 719 720 l = dataIn.readInt(); dataIn.skip(l); continue; 723 } 724 725 if (cmd == FINAL_DATA_BLOCK) { 727 if (!ena) { 728 throw new HeaderException("Broken header"); 729 } 730 l = dataIn.readInt(); dataIn.skip(l); continue; 733 } 734 735 if (cmd == HMAC_BLOCK) { 737 if (!ena) { 738 throw new HeaderException("Broken header"); 739 } 740 l = dataIn.readInt(); macCode = new byte[l]; dataIn.readFully(macCode); continue; 744 } 745 746 if (cmd == KEY_BLOCK) { 748 if (!ena) { 749 throw new HeaderException("Broken header"); 750 } 751 752 l = dataIn.readInt(); |