Search in sources :

Example 1 with AgileCertificateEntry

use of org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry in project poi by apache.

the class AgileEncryptor method confirmPassword.

@Override
public void confirmPassword(String password, byte[] keySpec, byte[] keySalt, byte[] verifier, byte[] verifierSalt, byte[] integritySalt) {
    AgileEncryptionVerifier ver = (AgileEncryptionVerifier) getEncryptionInfo().getVerifier();
    AgileEncryptionHeader header = (AgileEncryptionHeader) getEncryptionInfo().getHeader();
    ver.setSalt(verifierSalt);
    header.setKeySalt(keySalt);
    int blockSize = header.getBlockSize();
    pwHash = hashPassword(password, ver.getHashAlgorithm(), verifierSalt, ver.getSpinCount());
    /**
         * encryptedVerifierHashInput: This attribute MUST be generated by using the following steps:
         * 1. Generate a random array of bytes with the number of bytes used specified by the saltSize
         *    attribute.
         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
         *    consisting of the following bytes: 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, and 0x79.
         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
         *    integral multiple of blockSize bytes, pad the array with 0x00 to the next integral multiple of
         *    blockSize bytes.
         * 4. Use base64 to encode the result of step 3.
         */
    byte[] encryptedVerifier = hashInput(ver, pwHash, kVerifierInputBlock, verifier, Cipher.ENCRYPT_MODE);
    ver.setEncryptedVerifier(encryptedVerifier);
    /**
         * encryptedVerifierHashValue: This attribute MUST be generated by using the following steps:
         * 1. Obtain the hash value of the random array of bytes generated in step 1 of the steps for
         *    encryptedVerifierHashInput.
         * 2. Generate an encryption key as specified in section 2.3.4.11 by using the user-supplied password,
         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
         *    consisting of the following bytes: 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, and 0x4e.
         * 3. Encrypt the hash value obtained in step 1 by using the binary form of the saltValue attribute as
         *    an initialization vector as specified in section 2.3.4.12. If hashSize is not an integral multiple of
         *    blockSize bytes, pad the hash value with 0x00 to an integral multiple of blockSize bytes.
         * 4. Use base64 to encode the result of step 3.
         */
    MessageDigest hashMD = getMessageDigest(ver.getHashAlgorithm());
    byte[] hashedVerifier = hashMD.digest(verifier);
    byte[] encryptedVerifierHash = hashInput(ver, pwHash, kHashedVerifierBlock, hashedVerifier, Cipher.ENCRYPT_MODE);
    ver.setEncryptedVerifierHash(encryptedVerifierHash);
    /**
         * encryptedKeyValue: This attribute MUST be generated by using the following steps:
         * 1. Generate a random array of bytes that is the same size as specified by the
         *    Encryptor.KeyData.keyBits attribute of the parent element.
         * 2. Generate an encryption key as specified in section 2.3.4.11, using the user-supplied password,
         *    the binary byte array used to create the saltValue attribute, and a blockKey byte array
         *    consisting of the following bytes: 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, and 0xd6.
         * 3. Encrypt the random array of bytes generated in step 1 by using the binary form of the saltValue
         *    attribute as an initialization vector as specified in section 2.3.4.12. If the array of bytes is not an
         *    integral multiple of blockSize bytes, pad the array with 0x00 to an integral multiple of
         *    blockSize bytes.
         * 4. Use base64 to encode the result of step 3.
         */
    byte[] encryptedKey = hashInput(ver, pwHash, kCryptoKeyBlock, keySpec, Cipher.ENCRYPT_MODE);
    ver.setEncryptedKey(encryptedKey);
    SecretKey secretKey = new SecretKeySpec(keySpec, header.getCipherAlgorithm().jceId);
    setSecretKey(secretKey);
    /*
         * 2.3.4.14 DataIntegrity Generation (Agile Encryption)
         * 
         * The DataIntegrity element contained within an Encryption element MUST be generated by using
         * the following steps:
         * 1. Obtain the intermediate key by decrypting the encryptedKeyValue from a KeyEncryptor
         *    contained within the KeyEncryptors sequence. Use this key for encryption operations in the
         *    remaining steps of this section.
         * 2. Generate a random array of bytes, known as Salt, of the same length as the value of the
         *    KeyData.hashSize attribute.
         * 3. Encrypt the random array of bytes generated in step 2 by using the binary form of the
         *    KeyData.saltValue attribute and a blockKey byte array consisting of the following bytes:
         *    0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, and 0xf6 used to form an initialization vector as
         *    specified in section 2.3.4.12. If the array of bytes is not an integral multiple of blockSize
         *    bytes, pad the array with 0x00 to the next integral multiple of blockSize bytes.
         * 4. Assign the encryptedHmacKey attribute to the base64-encoded form of the result of step 3.
         * 5. Generate an HMAC, as specified in [RFC2104], of the encrypted form of the data (message),
         *    which the DataIntegrity element will verify by using the Salt generated in step 2 as the key.
         *    Note that the entire EncryptedPackage stream (1), including the StreamSize field, MUST be
         *    used as the message.
         * 6. Encrypt the HMAC as in step 3 by using a blockKey byte array consisting of the following bytes:
         *    0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, and 0x33.
         * 7.  Assign the encryptedHmacValue attribute to the base64-encoded form of the result of step 6. 
         */
    this.integritySalt = integritySalt.clone();
    try {
        byte[] vec = CryptoFunctions.generateIv(header.getHashAlgorithm(), header.getKeySalt(), kIntegrityKeyBlock, header.getBlockSize());
        Cipher cipher = getCipher(secretKey, header.getCipherAlgorithm(), header.getChainingMode(), vec, Cipher.ENCRYPT_MODE);
        byte[] hmacKey = getBlock0(this.integritySalt, getNextBlockSize(this.integritySalt.length, blockSize));
        byte[] encryptedHmacKey = cipher.doFinal(hmacKey);
        header.setEncryptedHmacKey(encryptedHmacKey);
        cipher = Cipher.getInstance("RSA");
        for (AgileCertificateEntry ace : ver.getCertificates()) {
            cipher.init(Cipher.ENCRYPT_MODE, ace.x509.getPublicKey());
            ace.encryptedKey = cipher.doFinal(getSecretKey().getEncoded());
            Mac x509Hmac = CryptoFunctions.getMac(header.getHashAlgorithm());
            x509Hmac.init(getSecretKey());
            ace.certVerifier = x509Hmac.doFinal(ace.x509.getEncoded());
        }
    } catch (GeneralSecurityException e) {
        throw new EncryptedDocumentException(e);
    }
}
Also used : AgileCertificateEntry(org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry) SecretKey(javax.crypto.SecretKey) EncryptedDocumentException(org.apache.poi.EncryptedDocumentException) SecretKeySpec(javax.crypto.spec.SecretKeySpec) GeneralSecurityException(java.security.GeneralSecurityException) Cipher(javax.crypto.Cipher) CryptoFunctions.getCipher(org.apache.poi.poifs.crypt.CryptoFunctions.getCipher) MessageDigest(java.security.MessageDigest) CryptoFunctions.getMessageDigest(org.apache.poi.poifs.crypt.CryptoFunctions.getMessageDigest) Mac(javax.crypto.Mac)

Example 2 with AgileCertificateEntry

use of org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry in project poi by apache.

the class AgileDecryptor method verifyPassword.

/**
     * instead of a password, it's also possible to decrypt via certificate.
     * Warning: this code is experimental and hasn't been validated
     * 
     * @see <a href="http://social.msdn.microsoft.com/Forums/en-US/cc9092bb-0c82-4b5b-ae21-abf643bdb37c/agile-encryption-with-certificates">Agile encryption with certificates</a>
     *
     * @param keyPair
     * @param x509
     * @return true, when the data can be successfully decrypted with the given private key
     * @throws GeneralSecurityException
     */
public boolean verifyPassword(KeyPair keyPair, X509Certificate x509) throws GeneralSecurityException {
    AgileEncryptionVerifier ver = (AgileEncryptionVerifier) getEncryptionInfo().getVerifier();
    AgileEncryptionHeader header = (AgileEncryptionHeader) getEncryptionInfo().getHeader();
    HashAlgorithm hashAlgo = header.getHashAlgorithm();
    CipherAlgorithm cipherAlgo = header.getCipherAlgorithm();
    int blockSize = header.getBlockSize();
    AgileCertificateEntry ace = null;
    for (AgileCertificateEntry aceEntry : ver.getCertificates()) {
        if (x509.equals(aceEntry.x509)) {
            ace = aceEntry;
            break;
        }
    }
    if (ace == null) {
        return false;
    }
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
    byte[] keyspec = cipher.doFinal(ace.encryptedKey);
    SecretKeySpec secretKey = new SecretKeySpec(keyspec, ver.getCipherAlgorithm().jceId);
    Mac x509Hmac = CryptoFunctions.getMac(hashAlgo);
    x509Hmac.init(secretKey);
    byte[] certVerifier = x509Hmac.doFinal(ace.x509.getEncoded());
    byte[] vec = CryptoFunctions.generateIv(hashAlgo, header.getKeySalt(), kIntegrityKeyBlock, blockSize);
    cipher = getCipher(secretKey, cipherAlgo, header.getChainingMode(), vec, Cipher.DECRYPT_MODE);
    byte[] hmacKey = cipher.doFinal(header.getEncryptedHmacKey());
    hmacKey = getBlock0(hmacKey, hashAlgo.hashSize);
    vec = CryptoFunctions.generateIv(hashAlgo, header.getKeySalt(), kIntegrityValueBlock, blockSize);
    cipher = getCipher(secretKey, cipherAlgo, header.getChainingMode(), vec, Cipher.DECRYPT_MODE);
    byte[] hmacValue = cipher.doFinal(header.getEncryptedHmacValue());
    hmacValue = getBlock0(hmacValue, hashAlgo.hashSize);
    if (Arrays.equals(ace.certVerifier, certVerifier)) {
        setSecretKey(secretKey);
        setIntegrityHmacKey(hmacKey);
        setIntegrityHmacValue(hmacValue);
        return true;
    } else {
        return false;
    }
}
Also used : CipherAlgorithm(org.apache.poi.poifs.crypt.CipherAlgorithm) AgileCertificateEntry(org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry) SecretKeySpec(javax.crypto.spec.SecretKeySpec) Cipher(javax.crypto.Cipher) CryptoFunctions.getCipher(org.apache.poi.poifs.crypt.CryptoFunctions.getCipher) Mac(javax.crypto.Mac) HashAlgorithm(org.apache.poi.poifs.crypt.HashAlgorithm)

Example 3 with AgileCertificateEntry

use of org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry in project poi by apache.

the class AgileEncryptor method createEncryptionDocument.

protected EncryptionDocument createEncryptionDocument() {
    AgileEncryptionVerifier ver = (AgileEncryptionVerifier) getEncryptionInfo().getVerifier();
    AgileEncryptionHeader header = (AgileEncryptionHeader) getEncryptionInfo().getHeader();
    EncryptionDocument ed = EncryptionDocument.Factory.newInstance();
    CTEncryption edRoot = ed.addNewEncryption();
    CTKeyData keyData = edRoot.addNewKeyData();
    CTKeyEncryptors keyEncList = edRoot.addNewKeyEncryptors();
    CTKeyEncryptor keyEnc = keyEncList.addNewKeyEncryptor();
    keyEnc.setUri(passwordUri);
    CTPasswordKeyEncryptor keyPass = keyEnc.addNewEncryptedPasswordKey();
    keyPass.setSpinCount(ver.getSpinCount());
    keyData.setSaltSize(header.getBlockSize());
    keyPass.setSaltSize(ver.getBlockSize());
    keyData.setBlockSize(header.getBlockSize());
    keyPass.setBlockSize(ver.getBlockSize());
    keyData.setKeyBits(header.getKeySize());
    keyPass.setKeyBits(ver.getKeySize());
    keyData.setHashSize(header.getHashAlgorithm().hashSize);
    keyPass.setHashSize(ver.getHashAlgorithm().hashSize);
    // header and verifier have to have the same cipher algorithm
    if (!header.getCipherAlgorithm().xmlId.equals(ver.getCipherAlgorithm().xmlId)) {
        throw new EncryptedDocumentException("Cipher algorithm of header and verifier have to match");
    }
    STCipherAlgorithm.Enum xmlCipherAlgo = STCipherAlgorithm.Enum.forString(header.getCipherAlgorithm().xmlId);
    if (xmlCipherAlgo == null) {
        throw new EncryptedDocumentException("CipherAlgorithm " + header.getCipherAlgorithm() + " not supported.");
    }
    keyData.setCipherAlgorithm(xmlCipherAlgo);
    keyPass.setCipherAlgorithm(xmlCipherAlgo);
    switch(header.getChainingMode()) {
        case cbc:
            keyData.setCipherChaining(STCipherChaining.CHAINING_MODE_CBC);
            keyPass.setCipherChaining(STCipherChaining.CHAINING_MODE_CBC);
            break;
        case cfb:
            keyData.setCipherChaining(STCipherChaining.CHAINING_MODE_CFB);
            keyPass.setCipherChaining(STCipherChaining.CHAINING_MODE_CFB);
            break;
        default:
            throw new EncryptedDocumentException("ChainingMode " + header.getChainingMode() + " not supported.");
    }
    keyData.setHashAlgorithm(mapHashAlgorithm(header.getHashAlgorithm()));
    keyPass.setHashAlgorithm(mapHashAlgorithm(ver.getHashAlgorithm()));
    keyData.setSaltValue(header.getKeySalt());
    keyPass.setSaltValue(ver.getSalt());
    keyPass.setEncryptedVerifierHashInput(ver.getEncryptedVerifier());
    keyPass.setEncryptedVerifierHashValue(ver.getEncryptedVerifierHash());
    keyPass.setEncryptedKeyValue(ver.getEncryptedKey());
    CTDataIntegrity hmacData = edRoot.addNewDataIntegrity();
    hmacData.setEncryptedHmacKey(header.getEncryptedHmacKey());
    hmacData.setEncryptedHmacValue(header.getEncryptedHmacValue());
    for (AgileCertificateEntry ace : ver.getCertificates()) {
        keyEnc = keyEncList.addNewKeyEncryptor();
        keyEnc.setUri(certificateUri);
        CTCertificateKeyEncryptor certData = keyEnc.addNewEncryptedCertificateKey();
        try {
            certData.setX509Certificate(ace.x509.getEncoded());
        } catch (CertificateEncodingException e) {
            throw new EncryptedDocumentException(e);
        }
        certData.setEncryptedKeyValue(ace.encryptedKey);
        certData.setCertVerifier(ace.certVerifier);
    }
    return ed;
}
Also used : AgileCertificateEntry(org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry) EncryptedDocumentException(org.apache.poi.EncryptedDocumentException) CTEncryption(com.microsoft.schemas.office.x2006.encryption.CTEncryption) CTDataIntegrity(com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity) STCipherAlgorithm(com.microsoft.schemas.office.x2006.encryption.STCipherAlgorithm) EncryptionDocument(com.microsoft.schemas.office.x2006.encryption.EncryptionDocument) CertificateEncodingException(java.security.cert.CertificateEncodingException) CTCertificateKeyEncryptor(com.microsoft.schemas.office.x2006.keyEncryptor.certificate.CTCertificateKeyEncryptor) CTKeyEncryptor(com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptor) CTKeyEncryptors(com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptors) CTPasswordKeyEncryptor(com.microsoft.schemas.office.x2006.keyEncryptor.password.CTPasswordKeyEncryptor) CTKeyData(com.microsoft.schemas.office.x2006.encryption.CTKeyData)

Aggregations

AgileCertificateEntry (org.apache.poi.poifs.crypt.agile.AgileEncryptionVerifier.AgileCertificateEntry)3 Cipher (javax.crypto.Cipher)2 Mac (javax.crypto.Mac)2 SecretKeySpec (javax.crypto.spec.SecretKeySpec)2 EncryptedDocumentException (org.apache.poi.EncryptedDocumentException)2 CryptoFunctions.getCipher (org.apache.poi.poifs.crypt.CryptoFunctions.getCipher)2 CTDataIntegrity (com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity)1 CTEncryption (com.microsoft.schemas.office.x2006.encryption.CTEncryption)1 CTKeyData (com.microsoft.schemas.office.x2006.encryption.CTKeyData)1 CTKeyEncryptor (com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptor)1 CTKeyEncryptors (com.microsoft.schemas.office.x2006.encryption.CTKeyEncryptors)1 EncryptionDocument (com.microsoft.schemas.office.x2006.encryption.EncryptionDocument)1 STCipherAlgorithm (com.microsoft.schemas.office.x2006.encryption.STCipherAlgorithm)1 CTCertificateKeyEncryptor (com.microsoft.schemas.office.x2006.keyEncryptor.certificate.CTCertificateKeyEncryptor)1 CTPasswordKeyEncryptor (com.microsoft.schemas.office.x2006.keyEncryptor.password.CTPasswordKeyEncryptor)1 GeneralSecurityException (java.security.GeneralSecurityException)1 MessageDigest (java.security.MessageDigest)1 CertificateEncodingException (java.security.cert.CertificateEncodingException)1 SecretKey (javax.crypto.SecretKey)1 CipherAlgorithm (org.apache.poi.poifs.crypt.CipherAlgorithm)1