Repository: servo/servo
File: components/script/dom/subtlecrypto/aes_operation.rs (Rust)

Code before:
    // Step 2. If the length of ciphertext is zero or is not a multiple of 16 bytes, then throw an
    // OperationError.
    if ciphertext.is_empty() {
        return Err(Error::Operation(Some("The ciphertext is empty".into())));
    }
    if ciphertext.len() % 16 != 0 {
        return Err(Error::Operation(Some(
            "The ciphertext length is not a multiple of 16 bytes".into(),
        )));
    }

    // Step 3. Let paddedPlaintext be the result of performing the CBC Decryption operation
    // described in Section 6.2 of [NIST-SP800-38A] using AES as the block cipher, the iv member of
    // normalizedAlgorithm as the IV input parameter and ciphertext as the input ciphertext.
    // Step 4. Let p be the value of the last octet of paddedPlaintext.
    // Step 5. If p is zero or greater than 16, or if any of the last p octets of paddedPlaintext
    // have a value which is not p, then throw an OperationError.
    // Step 6. Let plaintext be the result of removing p octets from the end of paddedPlaintext.
    let mut ciphertext = Vec::from(ciphertext);
    let iv = GenericArray::from_slice(&normalized_algorithm.iv);
    let plaintext = match key.handle() {
        Handle::Aes128(data) => {
            let key_data = GenericArray::from_slice(data);
            Aes128CbcDec::new(key_data, iv)
                .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
                .map_err(|err| Error::Operation(Some(err.to_string())))?
        },
        Handle::Aes192(data) => {
            let key_data = GenericArray::from_slice(data);
            Aes192CbcDec::new(key_data, iv)
                .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
                .map_err(|err| Error::Operation(Some(err.to_string())))?
        },
        Handle::Aes256(data) => {
            let key_data = GenericArray::from_slice(data);
            Aes256CbcDec::new(key_data, iv)
                .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
                .map_err(|err| Error::Operation(Some(err.to_string())))?
        },
        _ => return Err(Error::Data(Some("The key is not an AES key".into()))),
    };

    // Step 7. Return plaintext.
    Ok(plaintext.to_vec())
}

/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-generate-key>
pub(crate) fn generate_key_aes_cbc(
    global: &GlobalScope,
    normalized_algorithm: &SubtleAesKeyGenParams,
    extractable: bool,

Review comment (bug):
`fmt::Display` of `UnpadError` only returns a message "Unpad Error", which is a little bit vague in servo's context. Perhaps using a message like "Failed to perform CBC decryption" would be good enough.

Code after:
    // Step 2. If the length of ciphertext is zero or is not a multiple of 16 bytes, then throw an
    // OperationError.
    if ciphertext.is_empty() {
        return Err(Error::Operation(Some("The ciphertext is empty".into())));
    }
    if ciphertext.len() % 16 != 0 {
        return Err(Error::Operation(Some(
            "The ciphertext length is not a multiple of 16 bytes".into(),
        )));
    }

    // Step 3. Let paddedPlaintext be the result of performing the CBC Decryption operation
    // described in Section 6.2 of [NIST-SP800-38A] using AES as the block cipher, the iv member of
    // normalizedAlgorithm as the IV input parameter and ciphertext as the input ciphertext.
    // Step 4. Let p be the value of the last octet of paddedPlaintext.
    // Step 5. If p is zero or greater than 16, or if any of the last p octets of paddedPlaintext
    // have a value which is not p, then throw an OperationError.
    // Step 6. Let plaintext be the result of removing p octets from the end of paddedPlaintext.
    let mut ciphertext = Vec::from(ciphertext);
    let iv = GenericArray::from_slice(&normalized_algorithm.iv);
    let plaintext = match key.handle() {
        Handle::Aes128(data) => {
            let key_data = GenericArray::from_slice(data);
            Aes128CbcDec::new(key_data, iv)
                .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
                .map_err(|_| Error::Operation(Some("Failed to perform CBC decryption".into())))?
        },
        Handle::Aes192(data) => {
            let key_data = GenericArray::from_slice(data);
            Aes192CbcDec::new(key_data, iv)
                .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
                .map_err(|_| Error::Operation(Some("Failed to perform CBC decryption".into())))?
        },
        Handle::Aes256(data) => {
            let key_data = GenericArray::from_slice(data);
            Aes256CbcDec::new(key_data, iv)
                .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
                .map_err(|_| Error::Operation(Some("Failed to perform CBC decryption".into())))?
        },
        _ => return Err(Error::Data(Some("The key is not an AES key".into()))),
    };

    // Step 7. Return plaintext.
    Ok(plaintext.to_vec())
}

/// <https://w3c.github.io/webcrypto/#aes-cbc-operations-generate-key>
pub(crate) fn generate_key_aes_cbc(
    global: &GlobalScope,
    normalized_algorithm: &SubtleAesKeyGenParams,
    extractable: bool,