@Override protected Cipher initCipherForBlock(Cipher cipher, int block, boolean lastChunk) throws GeneralSecurityException { return XORDecryptor.initCipherForBlock(cipher, block, getEncryptionInfo(), getSecretKey(), Cipher.ENCRYPT_MODE); }
@Override protected Cipher initCipherForBlock(Cipher existing, int block) throws GeneralSecurityException { return XORDecryptor.this.initCipherForBlock(existing, block); }
@Override public void confirmPassword(String password, byte keySpec[], byte keySalt[], byte verifier[], byte verifierSalt[], byte integritySalt[]) { confirmPassword(password); }
@Override protected int invokeCipher(int totalBytes, boolean doFinal) { final int pos = (int)getPos(); final byte xorArray[] = getEncryptionInfo().getDecryptor().getSecretKey().getEncoded(); final byte chunk[] = getChunk(); final byte plain[] = getPlain(); final int posInChunk = pos & getChunkMask(); value = rotateLeft(value, 3); value ^= xorArray[(xorArrayIndex+i) & 0x0F]; chunk[posInChunk+i] = value;
@Override public void initialize(EncryptionInfo info, LittleEndianInput dis) throws IOException { info.setHeader(new XOREncryptionHeader()); info.setVerifier(new XOREncryptionVerifier(dis)); Decryptor dec = new XORDecryptor(); dec.setEncryptionInfo(info); info.setDecryptor(dec); Encryptor enc = new XOREncryptor(); enc.setEncryptionInfo(info); info.setEncryptor(enc); }
/** * Decrypts a xor obfuscated byte array. * The data is decrypted in-place * * @see <a href="http://msdn.microsoft.com/en-us/library/dd908506.aspx">2.3.7.3 Binary Document XOR Data Transformation Method 1</a> */ @Override public void setNextRecordSize(int recordSize) { final int pos = (int)getPos(); final byte chunk[] = getChunk(); final int chunkMask = getChunkMask(); recordStart = pos; recordEnd = recordStart+recordSize; int nextBytes = Math.min(recordSize, chunk.length-(pos & chunkMask)); invokeCipher(nextBytes, true); } }
@Override public void confirmPassword(String password) { int keyComp = CryptoFunctions.createXorKey1(password); int verifierComp = CryptoFunctions.createXorVerifier1(password); byte xorArray[] = CryptoFunctions.createXorArray1(password); byte shortBuf[] = new byte[2]; XOREncryptionVerifier ver = (XOREncryptionVerifier)getEncryptionInfo().getVerifier(); LittleEndian.putUShort(shortBuf, 0, keyComp); ver.setEncryptedKey(shortBuf); LittleEndian.putUShort(shortBuf, 0, verifierComp); ver.setEncryptedVerifier(shortBuf); setSecretKey(new SecretKeySpec(xorArray, "XOR")); }
@Override public boolean verifyPassword(String password) { XOREncryptionVerifier ver = (XOREncryptionVerifier)getEncryptionInfo().getVerifier(); int keyVer = LittleEndian.getUShort(ver.getEncryptedKey()); int verifierVer = LittleEndian.getUShort(ver.getEncryptedVerifier()); int keyComp = CryptoFunctions.createXorKey1(password); int verifierComp = CryptoFunctions.createXorVerifier1(password); if (keyVer == keyComp && verifierVer == verifierComp) { byte xorArray[] = CryptoFunctions.createXorArray1(password); setSecretKey(new SecretKeySpec(xorArray, "XOR")); return true; } else { return false; } }
final BitSet plainBytes = getPlainByteFlags(); final byte xorArray[] = getEncryptionInfo().getEncryptor().getSecretKey().getEncoded(); final byte chunk[] = getChunk(); final byte plain[] = (plainBytes.isEmpty()) ? null : chunk.clone(); byte value = chunk[i]; value ^= xorArray[(xorArrayIndex++) & 0x0F]; value = rotateLeft(value, 8-3); chunk[i] = value;
@Override public void setNextRecordSize(int recordSize, boolean isPlain) { if (recordEnd > 0 && !isPlain) { // encrypt last record invokeCipher((int)getPos(), true); } recordStart = (int)getTotalPos()+4; recordEnd = recordStart+recordSize; }
protected XOREncryptionVerifier() { setEncryptedKey(new byte[2]); setEncryptedVerifier(new byte[2]); }
@Override public void write(LittleEndianByteArrayOutputStream bos) { bos.write(getEncryptedKey()); bos.write(getEncryptedVerifier()); }
@SuppressWarnings("resource") @Override public void serialize(LittleEndianOutput out) { out.writeShort(encryptionType); byte data[] = new byte[1024]; LittleEndianByteArrayOutputStream bos = new LittleEndianByteArrayOutputStream(data, 0); // NOSONAR switch (encryptionInfo.getEncryptionMode()) { case xor: ((XOREncryptionHeader)encryptionInfo.getHeader()).write(bos); ((XOREncryptionVerifier)encryptionInfo.getVerifier()).write(bos); break; case binaryRC4: out.writeShort(encryptionInfo.getVersionMajor()); out.writeShort(encryptionInfo.getVersionMinor()); ((BinaryRC4EncryptionHeader)encryptionInfo.getHeader()).write(bos); ((BinaryRC4EncryptionVerifier)encryptionInfo.getVerifier()).write(bos); break; case cryptoAPI: out.writeShort(encryptionInfo.getVersionMajor()); out.writeShort(encryptionInfo.getVersionMinor()); out.writeInt(encryptionInfo.getEncryptionFlags()); ((CryptoAPIEncryptionHeader)encryptionInfo.getHeader()).write(bos); ((CryptoAPIEncryptionVerifier)encryptionInfo.getVerifier()).write(bos); break; default: throw new EncryptedDocumentException("not supported"); } out.write(data, 0, bos.getWriteIndex()); }
@Override public XORCipherOutputStream getDataStream(OutputStream stream, int initialOffset) throws IOException, GeneralSecurityException { return new XORCipherOutputStream(stream, initialOffset); }
@Override public InputStream getDataStream(InputStream stream, int size, int initialPos) throws IOException, GeneralSecurityException { return new XORCipherInputStream(stream, initialPos); }
@Override public void flush() throws IOException { setNextRecordSize(0, true); super.flush(); }
@Override public void initialize(EncryptionInfo info, CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) { info.setHeader(new XOREncryptionHeader()); info.setVerifier(new XOREncryptionVerifier()); Decryptor dec = new XORDecryptor(); dec.setEncryptionInfo(info); info.setDecryptor(dec); Encryptor enc = new XOREncryptor(); enc.setEncryptionInfo(info); info.setEncryptor(enc); } }
@Override protected Cipher initCipherForBlock(Cipher cipher, int block, boolean lastChunk) throws GeneralSecurityException { return XORDecryptor.initCipherForBlock(cipher, block, getEncryptionInfo(), getSecretKey(), Cipher.ENCRYPT_MODE); }
protected XOREncryptionVerifier(LittleEndianInput is) { /** * key (2 bytes): An unsigned integer that specifies the obfuscation key. * See [MS-OFFCRYPTO], 2.3.6.2 section, the first step of initializing XOR * array where it describes the generation of 16-bit XorKey value. */ byte key[] = new byte[2]; is.readFully(key); setEncryptedKey(key); /** * verificationBytes (2 bytes): An unsigned integer that specifies * the password verification identifier. */ byte verifier[] = new byte[2]; is.readFully(verifier); setEncryptedVerifier(verifier); }
@Override public OutputStream getDataStream(DirectoryNode dir) throws IOException, GeneralSecurityException { return new XORCipherOutputStream(dir); }