@Override public CryptoAPIEncryptionVerifier clone() throws CloneNotSupportedException { return (CryptoAPIEncryptionVerifier)super.clone(); } }
protected StandardEncryptionVerifier(CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) { setCipherAlgorithm(cipherAlgorithm); setHashAlgorithm(hashAlgorithm); setChainingMode(chainingMode); setSpinCount(SPIN_COUNT); verifierHashSize = hashAlgorithm.hashSize; }
@Override protected void setSalt(byte salt[]) { super.setSalt(salt); }
protected StandardEncryptionVerifier(LittleEndianInput is, StandardEncryptionHeader header) { int saltSize = is.readInt(); if (saltSize!=16) { throw new RuntimeException("Salt size != 16 !?"); } byte salt[] = new byte[16]; is.readFully(salt); setSalt(salt); byte encryptedVerifier[] = new byte[16]; is.readFully(encryptedVerifier); setEncryptedVerifier(encryptedVerifier); verifierHashSize = is.readInt(); byte encryptedVerifierHash[] = new byte[header.getCipherAlgorithm().encryptedVerifierHashLength]; is.readFully(encryptedVerifierHash); setEncryptedVerifierHash(encryptedVerifierHash); setSpinCount(SPIN_COUNT); setCipherAlgorithm(header.getCipherAlgorithm()); setChainingMode(header.getChainingMode()); setEncryptedKey(null); setHashAlgorithm(header.getHashAlgorithm()); }
protected StandardEncryptionHeader(CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) { setCipherAlgorithm(cipherAlgorithm); setHashAlgorithm(hashAlgorithm); setKeySize(keyBits); setBlockSize(blockSize); setCipherProvider(cipherAlgorithm.provider); setFlags(flagCryptoAPI.setBoolean(0, true) | flagAES.setBoolean(0, cipherAlgorithm.provider == CipherProvider.aes)); // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb931357(v=vs.85).aspx for a full list // setCspName("Microsoft Enhanced RSA and AES Cryptographic Provider"); }
throw new EncryptedDocumentException("KeySize "+keyBits+" not allowed for Cipher "+ cipherAlgorithm); info.setHeader(new StandardEncryptionHeader(cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode)); info.setVerifier(new StandardEncryptionVerifier(cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode)); StandardDecryptor dec = new StandardDecryptor(); dec.setEncryptionInfo(info); info.setDecryptor(dec); StandardEncryptor enc = new StandardEncryptor(); enc.setEncryptionInfo(info); info.setEncryptor(enc);
/** * initialize the builder from a stream */ @Override public void initialize(EncryptionInfo info, LittleEndianInput dis) throws IOException { /* int hSize = */ dis.readInt(); StandardEncryptionHeader header = new StandardEncryptionHeader(dis); info.setHeader(header); info.setVerifier(new StandardEncryptionVerifier(dis, header)); if (info.getVersionMinor() == 2 && (info.getVersionMajor() == 3 || info.getVersionMajor() == 4)) { StandardDecryptor dec = new StandardDecryptor(); dec.setEncryptionInfo(info); info.setDecryptor(dec); } }
@Override public void write(LittleEndianByteArrayOutputStream bos) { // see [MS-OFFCRYPTO] - 2.3.4.9 byte salt[] = getSalt(); assert(salt.length == 16); bos.writeInt(salt.length); // salt size bos.write(salt); // The resulting Verifier value MUST be an array of 16 bytes. byte encryptedVerifier[] = getEncryptedVerifier(); assert(encryptedVerifier.length == 16); bos.write(encryptedVerifier); // The number of bytes used by the decrypted Verifier hash is given by // the VerifierHashSize field, which MUST be 20 bos.writeInt(20); // EncryptedVerifierHash: An array of bytes that contains the encrypted form of the hash of // the randomly generated Verifier value. The length of the array MUST be the size of the // encryption block size multiplied by the number of blocks needed to encrypt the hash of the // Verifier. If the encryption algorithm is RC4, the length MUST be 20 bytes. If the encryption // algorithm is AES, the length MUST be 32 bytes. After decrypting the EncryptedVerifierHash // field, only the first VerifierHashSize bytes MUST be used. byte encryptedVerifierHash[] = getEncryptedVerifierHash(); assert(encryptedVerifierHash.length == getCipherAlgorithm().encryptedVerifierHashLength); bos.write(encryptedVerifierHash); }
@Override public OutputStream getDataStream(final DirectoryNode dir) throws IOException, GeneralSecurityException { createEncryptionInfoEntry(dir); DataSpaceMapUtils.addDefaultDataSpace(dir); return new StandardCipherOutputStream(dir); }
protected int getKeySizeInBytes() { return getEncryptionInfo().getHeader().getKeySize()/8; }
@Override protected void setEncryptedVerifierHash(byte encryptedVerifierHash[]) { super.setEncryptedVerifierHash(encryptedVerifierHash); }
@Override public CryptoAPIEncryptionHeader clone() throws CloneNotSupportedException { return (CryptoAPIEncryptionHeader)super.clone(); } }
@Override protected void setEncryptedVerifier(byte encryptedVerifier[]) { super.setEncryptedVerifier(encryptedVerifier); }
@Override public void close() throws IOException { // the CipherOutputStream adds the padding bytes on close() super.close(); writeToPOIFS(); }
@Override public void confirmPassword(String password) { // see [MS-OFFCRYPTO] - 2.3.3 EncryptionVerifier Random r = new SecureRandom(); byte[] salt = new byte[16], verifier = new byte[16]; r.nextBytes(salt); r.nextBytes(verifier); confirmPassword(password, null, null, salt, verifier, null); }
@SuppressWarnings("resource") private StandardCipherOutputStream(DirectoryNode dir, File fileOut) throws IOException { // although not documented, we need the same padding as with agile encryption // and instead of calculating the missing bytes for the block size ourselves // we leave it up to the CipherOutputStream, which generates/saves them on close() // ... we can't use "NoPadding" here // // see also [MS-OFFCRYPT] - 2.3.4.15 // The final data block MUST be padded to the next integral multiple of the // KeyData.blockSize value. Any padding bytes can be used. Note that the StreamSize // field of the EncryptedPackage field specifies the number of bytes of // unencrypted data as specified in section 2.3.4.4. super( new CipherOutputStream(new FileOutputStream(fileOut), getCipher(getSecretKey(), "PKCS5Padding")) ); this.fileOut = fileOut; this.dir = dir; }
private Cipher getCipher(SecretKey key) { EncryptionHeader em = getEncryptionInfo().getHeader(); ChainingMode cm = em.getChainingMode(); assert(cm == ChainingMode.ecb); return CryptoFunctions.getCipher(key, em.getCipherAlgorithm(), cm, null, Cipher.DECRYPT_MODE); }
protected void createEncryptionInfoEntry(DirectoryNode dir) throws IOException { final EncryptionInfo info = getEncryptionInfo(); final StandardEncryptionHeader header = (StandardEncryptionHeader)info.getHeader(); final StandardEncryptionVerifier verifier = (StandardEncryptionVerifier)info.getVerifier(); EncryptionRecord er = new EncryptionRecord(){ @Override public void write(LittleEndianByteArrayOutputStream bos) { bos.writeShort(info.getVersionMajor()); bos.writeShort(info.getVersionMinor()); bos.writeInt(info.getEncryptionFlags()); header.write(bos); verifier.write(bos); } }; createEncryptionEntry(dir, "EncryptionInfo", er); // TODO: any properties??? }
private Cipher getCipher(SecretKey key, String padding) { EncryptionVerifier ver = getEncryptionInfo().getVerifier(); return CryptoFunctions.getCipher(key, ver.getCipherAlgorithm(), ver.getChainingMode(), null, Cipher.ENCRYPT_MODE, padding); }