Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.bouncycastle.crypto.test;
  
 
 public class AEADTestUtil
 {
     public static void testTampering(Test testAEADBlockCipher cipherCipherParameters params)
         throws InvalidCipherTextException
     {
         byte[] plaintext = new byte[1000];
         for (int i = 0; i < plaintext.lengthi++)
         {
             plaintext[i] = (byte)i;
         }
         cipher.init(trueparams);
 
         byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)];
         int len = cipher.processBytes(plaintext, 0, plaintext.lengthciphertext, 0);
         cipher.doFinal(ciphertextlen);
 
         int macLength = cipher.getMac().length;
 
         // Test tampering with a single byte
         cipher.init(falseparams);
         byte[] tampered = new byte[ciphertext.length];
         byte[] output = new byte[plaintext.length];
         System.arraycopy(ciphertext, 0, tampered, 0, tampered.length);
         tampered[0] += 1;
 
         cipher.processBytes(tampered, 0, tampered.lengthoutput, 0);
         try
         {
             cipher.doFinal(output, 0);
             throw new TestFailedException(
                 new SimpleTestResult(falsetest + " : tampering of ciphertext not detected."));
         }
         catch (InvalidCipherTextException e)
         {
             // Expected
         }
 
         // Test truncation of ciphertext to < tag length
         cipher.init(falseparams);
         byte[] truncated = new byte[macLength - 1];
         System.arraycopy(ciphertext, 0, truncated, 0, truncated.length);
 
         cipher.processBytes(truncated, 0, truncated.lengthoutput, 0);
         try
         {
             cipher.doFinal(output, 0);
             fail(test"tampering of ciphertext not detected.");
         }
         catch (InvalidCipherTextException e)
         {
             // Expected
         }
     }
 
     private static void fail(Test testString message)
     {
         throw new TestFailedException(SimpleTestResult.failed(testmessage));
     }
 
     private static void fail(Test testString messageString expectedString result)
     {
         throw new TestFailedException(SimpleTestResult.failed(testmessageexpectedresult));
     }
 
     public static void testReset(Test testAEADBlockCipher cipher1AEADBlockCipher cipher2CipherParameters params)
         throws InvalidCipherTextException
     {
         cipher1.init(trueparams);
 
         byte[] plaintext = new byte[1000];
         byte[] ciphertext = new byte[cipher1.getOutputSize(plaintext.length)];
 
         // Establish baseline answer
         crypt(cipher1plaintextciphertext);
 
         // Test encryption resets
         checkReset(testcipher1paramstrueplaintextciphertext);
 
         // Test decryption resets with fresh instance
         cipher2.init(falseparams);
         checkReset(testcipher2paramsfalseciphertextplaintext);
     }
 
     private static void checkReset(Test test,
                                    AEADBlockCipher cipher,
                                   CipherParameters params,
                                   boolean encrypt,
                                   byte[] pretext,
                                   byte[] posttext)
        throws InvalidCipherTextException
    {
        // Do initial run
        byte[] output = new byte[posttext.length];
        crypt(cipherpretextoutput);
        // Check encrypt resets cipher
        crypt(cipherpretextoutput);
        if (!Arrays.areEqual(outputposttext))
        {
            fail(test, (encrypt ? "Encrypt" : "Decrypt") + " did not reset cipher.");
        }
        // Check init resets data
        cipher.processBytes(pretext, 0, 100, output, 0);
        cipher.init(encryptparams);
        try
        {
            crypt(cipherpretextoutput);
        }
        catch (DataLengthException e)
        {
            fail(test"Init did not reset data.");
        }
        if (!Arrays.areEqual(outputposttext))
        {
            fail(test"Init did not reset data."new String(Hex.encode(posttext)), new String(Hex.encode(output)));
        }
        // Check init resets AD
        cipher.processAADBytes(pretext, 0, 100);
        cipher.init(encryptparams);
        try
        {
            crypt(cipherpretextoutput);
        }
        catch (DataLengthException e)
        {
            fail(test"Init did not reset additional data.");
        }
        if (!Arrays.areEqual(outputposttext))
        {
            fail(test"Init did not reset additional data.");
        }
        // Check reset resets data
        cipher.processBytes(pretext, 0, 100, output, 0);
        cipher.reset();
        try
        {
            crypt(cipherpretextoutput);
        }
        catch (DataLengthException e)
        {
            fail(test"Init did not reset data.");
        }
        if (!Arrays.areEqual(outputposttext))
        {
            fail(test"Reset did not reset data.");
        }
        // Check reset resets AD
        cipher.processAADBytes(pretext, 0, 100);
        cipher.reset();
        try
        {
            crypt(cipherpretextoutput);
        }
        catch (DataLengthException e)
        {
            fail(test"Init did not reset data.");
        }
        if (!Arrays.areEqual(outputposttext))
        {
            fail(test"Reset did not reset additional data.");
        }
    }
    private static void crypt(AEADBlockCipher cipherbyte[] plaintextbyte[] output)
        throws InvalidCipherTextException
    {
        int len = cipher.processBytes(plaintext, 0, plaintext.lengthoutput, 0);
        cipher.doFinal(outputlen);
    }
    public static void testOutputSizes(Test testAEADBlockCipher cipherAEADParameters params)
        throws IllegalStateException,
    {
        int maxPlaintext = cipher.getUnderlyingCipher().getBlockSize() * 10;
        byte[] plaintext = new byte[maxPlaintext];
        byte[] ciphertext = new byte[maxPlaintext * 2];
        // Check output size calculations for truncated ciphertext lengths
        cipher.init(trueparams);
        cipher.doFinal(ciphertext, 0);
        int macLength = cipher.getMac().length;
        cipher.init(falseparams);
        for (int i = 0; i < macLengthi++)
        {
            cipher.reset();
            if (cipher.getUpdateOutputSize(i) != 0)
            {
                fail(test"AE cipher should not produce update output with ciphertext length <= macSize");
            }
            if (cipher.getOutputSize(i) != 0)
            {
                fail(test"AE cipher should not produce output with ciphertext length <= macSize");
            }
        }
        for (int i = 0; i < plaintext.lengthi++)
        {
            cipher.init(trueparams);
            int expectedCTUpdateSize = cipher.getUpdateOutputSize(i);
            int expectedCTOutputSize = cipher.getOutputSize(i);
            if (expectedCTUpdateSize < 0)
            {
                fail(test"Encryption update output size should not be < 0 for size " + i);
            }
            if (expectedCTOutputSize < 0)
            {
                fail(test"Encryption update output size should not be < 0 for size " + i);
            }
            int actualCTSize = cipher.processBytes(plaintext, 0, iciphertext, 0);
            if (expectedCTUpdateSize != actualCTSize)
            {
                fail(test"Encryption update output size did not match calculated for plaintext length " + i,
                        String.valueOf(expectedCTUpdateSize), String.valueOf(actualCTSize));
            }
            actualCTSize += cipher.doFinal(ciphertextactualCTSize);
            if (expectedCTOutputSize != actualCTSize)
            {
                fail(test"Encryption actual final output size did not match calculated for plaintext length " + i,
                        String.valueOf(expectedCTOutputSize), String.valueOf(actualCTSize));
            }
            cipher.init(falseparams);
            int expectedPTUpdateSize = cipher.getUpdateOutputSize(actualCTSize);
            int expectedPTOutputSize = cipher.getOutputSize(actualCTSize);
            if (expectedPTOutputSize != i)
            {
                fail(test"Decryption update output size did not original plaintext length " + i,
                        String.valueOf(expectedPTUpdateSize), String.valueOf(i));
            }
            int actualPTSize = cipher.processBytes(ciphertext, 0, actualCTSizeplaintext, 0);
            if (expectedPTUpdateSize != actualPTSize)
            {
                fail(test"Decryption update output size did not match calculated for plaintext length " + i,
                        String.valueOf(expectedPTUpdateSize), String.valueOf(actualPTSize));
            }
            actualPTSize += cipher.doFinal(plaintextactualPTSize);
            if (expectedPTOutputSize != actualPTSize)
            {
                fail(test"Decryption update output size did not match calculated for plaintext length " + i,
                        String.valueOf(expectedPTOutputSize), String.valueOf(actualPTSize));
            }
        }
    }
    public static void testBufferSizeChecks(Test testAEADBlockCipher cipherAEADParameters params)
        throws IllegalStateException,
    {
        int blockSize = cipher.getUnderlyingCipher().getBlockSize();
        int maxPlaintext = (blockSize * 10);
        byte[] plaintext = new byte[maxPlaintext];
        cipher.init(trueparams);
        int expectedUpdateOutputSize = cipher.getUpdateOutputSize(plaintext.length);
        byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)];
        try
        {
            cipher.processBytes(new byte[maxPlaintext - 1], 0, maxPlaintextnew byte[expectedUpdateOutputSize], 0);
            fail(test"processBytes should validate input buffer length");
        }
        catch (DataLengthException e)
        {
            // Expected
        }
        cipher.reset();
        if (expectedUpdateOutputSize > 0)
        {
            int outputTrigger = 0;
            // Process bytes until output would be produced
            for(int i = 0; i < plaintext.lengthi++) {
                if (cipher.getUpdateOutputSize(1) != 0)
                {
                    outputTrigger = i + 1;
                    break;
                }
                cipher.processByte(plaintext[i], ciphertext, 0);
            }
            if (outputTrigger == 0)
            {
                fail(test"Failed to find output trigger size");
            }
            try
            {
                cipher.processByte(plaintext[0], new byte[cipher.getUpdateOutputSize(1) - 1], 0);
                fail(test"Encrypt processByte should validate output buffer length");
            }
            catch (OutputLengthException e)
            {
                // Expected
            }
            cipher.reset();
            // Repeat checking with entire input at once
            try
            {
                cipher.processBytes(plaintext, 0, outputTrigger,
                        new byte[cipher.getUpdateOutputSize(outputTrigger) - 1], 0);
                fail(test"Encrypt processBytes should validate output buffer length");
            }
            catch (OutputLengthException e)
            {
                // Expected
            }
            cipher.reset();
        }
        // Remember the actual ciphertext for later
        int actualOutputSize = cipher.processBytes(plaintext, 0, plaintext.lengthciphertext, 0);
        actualOutputSize += cipher.doFinal(ciphertextactualOutputSize);
        int macSize = cipher.getMac().length;
        cipher.reset();
        try
        {
            cipher.processBytes(plaintext, 0, plaintext.lengthciphertext, 0);
            cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0);
            fail(test"Encrypt doFinal should validate output buffer length");
        }
        catch (OutputLengthException e)
        {
            // Expected
        }
        // Decryption tests
        cipher.init(falseparams);
        expectedUpdateOutputSize = cipher.getUpdateOutputSize(actualOutputSize);
        if (expectedUpdateOutputSize > 0)
        {
            // Process bytes until output would be produced
            int outputTrigger = 0;
            for (int i = 0; i < plaintext.lengthi++)
            {
                if (cipher.getUpdateOutputSize(1) != 0)
                {
                    outputTrigger = i + 1;
                    break;
                }
                cipher.processByte(ciphertext[i], plaintext, 0);
            }
            if (outputTrigger == 0)
            {
                fail(test"Failed to find output trigger size");
            }
            try
            {
                cipher.processByte(ciphertext[0], new byte[cipher.getUpdateOutputSize(1) - 1], 0);
                fail(test"Decrypt processByte should validate output buffer length");
            }
            catch (OutputLengthException e)
            {
                // Expected
            }
            cipher.reset();
            // Repeat test with processBytes
            try
            {
                cipher.processBytes(ciphertext, 0, outputTrigger,
                        new byte[cipher.getUpdateOutputSize(outputTrigger) - 1], 0);
                fail(test"Decrypt processBytes should validate output buffer length");
            }
            catch (OutputLengthException e)
            {
                // Expected
            }
        }
        cipher.reset();
        // Data less than mac length should fail before output length check
        try
        {
            // Assumes AE cipher on decrypt can't return any data until macSize bytes are received
            if (cipher.processBytes(ciphertext, 0, macSize - 1, plaintext, 0) != 0)
            {
                fail(test"AE cipher unexpectedly produced output");
            }
            cipher.doFinal(new byte[0], 0);
            fail(test"Decrypt doFinal should check ciphertext length");
        }
        catch (InvalidCipherTextException e)
        {
            // Expected
        }
        try
        {
            // Search through plaintext lengths until one is found that creates >= 1 buffered byte
            // during decryption of ciphertext for doFinal to handle
            for (int i = 2; i < plaintext.lengthi++)
            {
                cipher.init(trueparams);
                int encrypted = cipher.processBytes(plaintext, 0, iciphertext, 0);
                encrypted += cipher.doFinal(ciphertextencrypted);
                cipher.init(falseparams);
                cipher.processBytes(ciphertext, 0, encrypted - 1, plaintext, 0);
                if (cipher.processByte(ciphertext[encrypted - 1], plaintext, 0) == 0)
                {
                    cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0);
                    fail(test"Decrypt doFinal should check output length");
                    cipher.reset();
                    // Truncated Mac should be reported in preference to inability to output
                    // buffered plaintext byte
                    try
                    {
                        cipher.processBytes(ciphertext, 0, actualOutputSize - 1, plaintext, 0);
                        cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0);
                        fail(test"Decrypt doFinal should check ciphertext length");
                    }
                    catch (InvalidCipherTextException e)
                    {
                        // Expected
                    }
                    cipher.reset();
                }
            }
            fail(test"Decrypt doFinal test couldn't find a ciphertext length that buffered for doFinal");
        }
        catch (OutputLengthException e)
        {
            // Expected
        }
    }
    {
        return new AEADParameters(nullp.getMacSize(), p.getNonce(), p.getAssociatedText());
    }
New to GrepCode? Check out our FAQ X