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

package org.bouncycastle.crypto.engines;

import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.DataLengthException;
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 RFC3394WrapEngine implements Wrapper
{
    private static final byte[] DEFAULT_IV;
    private final BlockCipher engine;
    private final boolean wrapCipherMode;
    private final byte[] iv;
    private KeyParameter param;
    private boolean forWrapping;
    
    public RFC3394WrapEngine(final BlockCipher blockCipher) {
        this(blockCipher, false);
    }
    
    public RFC3394WrapEngine(final BlockCipher engine, final boolean b) {
        this.iv = new byte[8];
        this.param = null;
        this.forWrapping = true;
        this.engine = engine;
        this.wrapCipherMode = !b;
    }
    
    @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(RFC3394WrapEngine.DEFAULT_IV, 0, this.iv, 0, 8);
        }
        else if (parameters instanceof ParametersWithIV) {
            final ParametersWithIV parametersWithIV = (ParametersWithIV)parameters;
            final byte[] iv = parametersWithIV.getIV();
            if (iv.length != 8) {
                throw new IllegalArgumentException("IV not equal to 8");
            }
            this.param = (KeyParameter)parametersWithIV.getParameters();
            System.arraycopy(iv, 0, this.iv, 0, 8);
        }
    }
    
    @Override
    public String getAlgorithmName() {
        return this.engine.getAlgorithmName();
    }
    
    @Override
    public byte[] wrap(final byte[] array, final int n, final int n2) {
        if (!this.forWrapping) {
            throw new IllegalStateException("not set for wrapping");
        }
        if (n2 < 8) {
            throw new DataLengthException("wrap data must be at least 8 bytes");
        }
        final int n3 = n2 / 8;
        if (n3 * 8 != n2) {
            throw new DataLengthException("wrap data must be a multiple of 8 bytes");
        }
        this.engine.init(this.wrapCipherMode, this.param);
        final byte[] array2 = new byte[n2 + this.iv.length];
        System.arraycopy(this.iv, 0, array2, 0, this.iv.length);
        System.arraycopy(array, n, array2, this.iv.length, n2);
        if (n3 == 1) {
            this.engine.processBlock(array2, 0, array2, 0);
        }
        else {
            final byte[] array3 = new byte[8 + this.iv.length];
            for (int i = 0; i != 6; ++i) {
                for (int j = 1; j <= n3; ++j) {
                    System.arraycopy(array2, 0, array3, 0, this.iv.length);
                    System.arraycopy(array2, 8 * j, array3, this.iv.length, 8);
                    this.engine.processBlock(array3, 0, array3, 0);
                    for (int k = n3 * i + j, n4 = 1; k != 0; k >>>= 8, ++n4) {
                        final byte b = (byte)k;
                        final byte[] array4 = array3;
                        final int n5 = this.iv.length - n4;
                        array4[n5] ^= b;
                    }
                    System.arraycopy(array3, 0, array2, 0, 8);
                    System.arraycopy(array3, 8, array2, 8 * j, 8);
                }
            }
        }
        return array2;
    }
    
    @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");
        }
        if (n2 < 16) {
            throw new InvalidCipherTextException("unwrap data too short");
        }
        final int n3 = n2 / 8;
        if (n3 * 8 != n2) {
            throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
        }
        this.engine.init(!this.wrapCipherMode, this.param);
        final byte[] array2 = new byte[n2 - this.iv.length];
        final byte[] array3 = new byte[this.iv.length];
        final byte[] array4 = new byte[8 + this.iv.length];
        final int n4 = n3 - 1;
        if (n4 == 1) {
            this.engine.processBlock(array, n, array4, 0);
            System.arraycopy(array4, 0, array3, 0, this.iv.length);
            System.arraycopy(array4, this.iv.length, array2, 0, 8);
        }
        else {
            System.arraycopy(array, n, array3, 0, this.iv.length);
            System.arraycopy(array, n + this.iv.length, array2, 0, n2 - this.iv.length);
            for (int i = 5; i >= 0; --i) {
                for (int j = n4; j >= 1; --j) {
                    System.arraycopy(array3, 0, array4, 0, this.iv.length);
                    System.arraycopy(array2, 8 * (j - 1), array4, this.iv.length, 8);
                    for (int k = n4 * i + j, n5 = 1; k != 0; k >>>= 8, ++n5) {
                        final byte b = (byte)k;
                        final byte[] array5 = array4;
                        final int n6 = this.iv.length - n5;
                        array5[n6] ^= b;
                    }
                    this.engine.processBlock(array4, 0, array4, 0);
                    System.arraycopy(array4, 0, array3, 0, 8);
                    System.arraycopy(array4, 8, array2, 8 * (j - 1), 8);
                }
            }
        }
        if (n4 != 1) {
            if (!Arrays.constantTimeAreEqual(array3, this.iv)) {
                throw new InvalidCipherTextException("checksum failed");
            }
        }
        else if (!Arrays.constantTimeAreEqual(array3, this.iv)) {
            System.arraycopy(array, n, array3, 0, this.iv.length);
            System.arraycopy(array, n + this.iv.length, array2, 0, n2 - this.iv.length);
            for (int l = 5; l >= 0; --l) {
                System.arraycopy(array3, 0, array4, 0, this.iv.length);
                System.arraycopy(array2, 0, array4, this.iv.length, 8);
                for (int n7 = n4 * l + 1, n8 = 1; n7 != 0; n7 >>>= 8, ++n8) {
                    final byte b2 = (byte)n7;
                    final byte[] array6 = array4;
                    final int n9 = this.iv.length - n8;
                    array6[n9] ^= b2;
                }
                this.engine.processBlock(array4, 0, array4, 0);
                System.arraycopy(array4, 0, array3, 0, 8);
                System.arraycopy(array4, 8, array2, 0, 8);
            }
            if (!Arrays.constantTimeAreEqual(array3, this.iv)) {
                throw new InvalidCipherTextException("checksum failed");
            }
        }
        return array2;
    }
    
    static {
        DEFAULT_IV = new byte[] { -90, -90, -90, -90, -90, -90, -90, -90 };
    }
}
