/** * Fills the fields of verifier and header with the calculated hashes based * on the password and a random salt * * see [MS-OFFCRYPTO] - 2.3.4.7 ECMA-376 Document Encryption Key Generation */ public override void ConfirmPassword(String password, byte[] keySpec, byte[] keySalt, byte[] verifier, byte[] verifierSalt, byte[] integritySalt) { StandardEncryptionVerifier ver = builder.GetVerifier(); ver.SetSalt(verifierSalt); ISecretKey secretKey = StandardDecryptor.GenerateSecretKey(password, ver, GetKeySizeInBytes()); SetSecretKey(secretKey); Cipher cipher = GetCipher(secretKey, null); try { byte[] encryptedVerifier = cipher.DoFinal(verifier); MessageDigest hashAlgo = CryptoFunctions.GetMessageDigest(ver.HashAlgorithm); byte[] calcVerifierHash = hashAlgo.Digest(verifier); // 2.3.3 EncryptionVerifier ... // 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. int encVerHashSize = ver.CipherAlgorithm.encryptedVerifierHashLength; byte[] encryptedVerifierHash = cipher.DoFinal(Arrays.CopyOf(calcVerifierHash, encVerHashSize)); ver.SetEncryptedVerifier(encryptedVerifier); ver.SetEncryptedVerifierHash(encryptedVerifierHash); } catch (Exception e) { throw new EncryptedDocumentException("Password Confirmation failed", e); } }
/** * Initialize the builder from scratch */ public void Initialize(EncryptionInfo info, CipherAlgorithm cipherAlgorithm, HashAlgorithm hashAlgorithm, int keyBits, int blockSize, ChainingMode chainingMode) { this.info = info; if (cipherAlgorithm == null) { cipherAlgorithm = CipherAlgorithm.aes128; } if (cipherAlgorithm != CipherAlgorithm.aes128 && cipherAlgorithm != CipherAlgorithm.aes192 && cipherAlgorithm != CipherAlgorithm.aes256) { throw new EncryptedDocumentException("Standard encryption only supports AES128/192/256."); } if (hashAlgorithm == null) { hashAlgorithm = HashAlgorithm.sha1; } if (hashAlgorithm != HashAlgorithm.sha1) { throw new EncryptedDocumentException("Standard encryption only supports SHA-1."); } if (chainingMode == null) { chainingMode = ChainingMode.ecb; } if (chainingMode != ChainingMode.ecb) { throw new EncryptedDocumentException("Standard encryption only supports ECB chaining."); } if (keyBits == -1) { keyBits = cipherAlgorithm.defaultKeySize; } if (blockSize == -1) { blockSize = cipherAlgorithm.blockSize; } bool found = false; foreach (int ks in cipherAlgorithm.allowedKeySize) { found |= (ks == keyBits); } if (!found) { throw new EncryptedDocumentException("KeySize " + keyBits + " not allowed for Cipher " + cipherAlgorithm.ToString()); } header = new StandardEncryptionHeader(cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode); verifier = new StandardEncryptionVerifier(cipherAlgorithm, hashAlgorithm, keyBits, blockSize, chainingMode); decryptor = new StandardDecryptor(this); encryptor = new StandardEncryptor(this); }
/** * Initialize the builder from a stream */ public void Initialize(EncryptionInfo info, ILittleEndianInput dis) { this.info = info; int hSize = dis.ReadInt(); header = new StandardEncryptionHeader(dis); verifier = new StandardEncryptionVerifier(dis, header); if (info.VersionMinor == 2 && (info.VersionMajor == 3 || info.VersionMajor == 4)) { decryptor = new StandardDecryptor(this); } }