// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.crypto.engines;

import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.util.Pack;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.Wrapper;

public class RFC5649WrapEngine implements Wrapper
{
    private static final byte[] DEFAULT_IV;
    private final BlockCipher engine;
    private final byte[] preIV;
    private KeyParameter param;
    private boolean forWrapping;
    
    public RFC5649WrapEngine(final BlockCipher engine) {
        this.preIV = new byte[4];
        this.param = null;
        this.forWrapping = true;
        this.engine = engine;
    }
    
    @Override
    public void init(final boolean forWrapping, CipherParameters parameters) {
        this.forWrapping = forWrapping;
        if (parameters instanceof ParametersWithRandom) {
            parameters = ((ParametersWithRandom)parameters).getParameters();
        }
        if (parameters instanceof KeyParameter) {
            this.param = (KeyParameter)parameters;
            System.arraycopy(RFC5649WrapEngine.DEFAULT_IV, 0, this.preIV, 0, 4);
        }
        else if (parameters instanceof ParametersWithIV) {
            final ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
            final byte[] iv = parametersWithIV.getIV();
            if (iv.length != 4) {
                throw new IllegalArgumentException("IV length not equal to 4");
            }
            this.param = (KeyParameter)parametersWithIV.getParameters();
            System.arraycopy(iv, 0, this.preIV, 0, 4);
        }
    }
    
    @Override
    public String getAlgorithmName() {
        return this.engine.getAlgorithmName();
    }
    
    private byte[] padPlaintext(final byte[] array) {
        final int length = array.length;
        final int n = (8 - length % 8) % 8;
        final byte[] array2 = new byte[length + n];
        System.arraycopy(array, 0, array2, 0, length);
        if (n != 0) {
            System.arraycopy(new byte[n], 0, array2, length, n);
        }
        return array2;
    }
    
    @Override
    public byte[] wrap(final byte[] array, final int n, final int n2) {
        if (!this.forWrapping) {
            throw new IllegalStateException("not set for wrapping");
        }
        final byte[] array2 = new byte[8];
        System.arraycopy(this.preIV, 0, array2, 0, 4);
        Pack.intToBigEndian(n2, array2, 4);
        final byte[] array3 = new byte[n2];
        System.arraycopy(array, n, array3, 0, n2);
        final byte[] padPlaintext = this.padPlaintext(array3);
        if (padPlaintext.length == 8) {
            final byte[] array4 = new byte[padPlaintext.length + array2.length];
            System.arraycopy(array2, 0, array4, 0, array2.length);
            System.arraycopy(padPlaintext, 0, array4, array2.length, padPlaintext.length);
            this.engine.init(true, this.param);
            for (int i = 0, blockSize = this.engine.getBlockSize(); i < array4.length; i += blockSize) {
                this.engine.processBlock(array4, i, array4, i);
            }
            return array4;
        }
        final RFC3394WrapEngine rfc3394WrapEngine = new RFC3394WrapEngine(this.engine);
        rfc3394WrapEngine.init(true, new ParametersWithIV(this.param, array2));
        return rfc3394WrapEngine.wrap(padPlaintext, 0, padPlaintext.length);
    }
    
    @Override
    public byte[] unwrap(final byte[] array, final int n, final int n2) throws InvalidCipherTextException {
        if (this.forWrapping) {
            throw new IllegalStateException("not set for unwrapping");
        }
        final int n3 = n2 / 8;
        if (n3 * 8 != n2) {
            throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
        }
        if (n3 <= 1) {
            throw new InvalidCipherTextException("unwrap data must be at least 16 bytes");
        }
        final byte[] array2 = new byte[n2];
        System.arraycopy(array, n, array2, 0, n2);
        final byte[] array3 = new byte[n2];
        final byte[] array4 = new byte[8];
        byte[] rfc3394UnwrapNoIvCheck;
        if (n3 == 2) {
            this.engine.init(false, this.param);
            for (int i = 0, blockSize = this.engine.getBlockSize(); i < array2.length; i += blockSize) {
                this.engine.processBlock(array2, i, array3, i);
            }
            System.arraycopy(array3, 0, array4, 0, array4.length);
            rfc3394UnwrapNoIvCheck = new byte[array3.length - array4.length];
            System.arraycopy(array3, array4.length, rfc3394UnwrapNoIvCheck, 0, rfc3394UnwrapNoIvCheck.length);
        }
        else {
            rfc3394UnwrapNoIvCheck = this.rfc3394UnwrapNoIvCheck(array, n, n2, array4);
        }
        final byte[] array5 = new byte[4];
        System.arraycopy(array4, 0, array5, 0, 4);
        final int bigEndianToInt = Pack.bigEndianToInt(array4, 4);
        boolean constantTimeAreEqual = Arrays.constantTimeAreEqual(array5, this.preIV);
        final int length = rfc3394UnwrapNoIvCheck.length;
        if (bigEndianToInt <= length - 8) {
            constantTimeAreEqual = false;
        }
        if (bigEndianToInt > length) {
            constantTimeAreEqual = false;
        }
        int n4 = length - bigEndianToInt;
        if (n4 >= 8 || n4 < 0) {
            constantTimeAreEqual = false;
            n4 = 4;
        }
        final byte[] array6 = new byte[n4];
        final byte[] array7 = new byte[n4];
        System.arraycopy(rfc3394UnwrapNoIvCheck, rfc3394UnwrapNoIvCheck.length - n4, array7, 0, n4);
        if (!Arrays.constantTimeAreEqual(array7, array6)) {
            constantTimeAreEqual = false;
        }
        if (!constantTimeAreEqual) {
            throw new InvalidCipherTextException("checksum failed");
        }
        final byte[] array8 = new byte[bigEndianToInt];
        System.arraycopy(rfc3394UnwrapNoIvCheck, 0, array8, 0, array8.length);
        return array8;
    }
    
    private byte[] rfc3394UnwrapNoIvCheck(final byte[] array, final int n, final int n2, final byte[] array2) {
        final byte[] array3 = new byte[n2 - 8];
        final byte[] array4 = new byte[16];
        System.arraycopy(array, n, array4, 0, 8);
        System.arraycopy(array, n + 8, array3, 0, n2 - 8);
        this.engine.init(false, this.param);
        final int n3 = n2 / 8 - 1;
        for (int i = 5; i >= 0; --i) {
            for (int j = n3; j >= 1; --j) {
                System.arraycopy(array3, 8 * (j - 1), array4, 8, 8);
                for (int k = n3 * i + j, n4 = 1; k != 0; k >>>= 8, ++n4) {
                    final byte[] array5 = array4;
                    final int n5 = 8 - n4;
                    array5[n5] ^= (byte)k;
                }
                this.engine.processBlock(array4, 0, array4, 0);
                System.arraycopy(array4, 8, array3, 8 * (j - 1), 8);
            }
        }
        System.arraycopy(array4, 0, array2, 0, 8);
        return array3;
    }
    
    static {
        DEFAULT_IV = new byte[] { -90, 89, 89, -90 };
    }
}
