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

package org.bouncycastle.crypto.prng;

import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG;
import org.bouncycastle.crypto.prng.drbg.HMacSP800DRBG;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.prng.drbg.CTRSP800DRBG;
import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.Mac;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import java.security.SecureRandom;

public class SP800SecureRandomBuilder
{
    private final SecureRandom random;
    private final EntropySourceProvider entropySourceProvider;
    private byte[] personalizationString;
    private int securityStrength;
    private int entropyBitsRequired;
    
    public SP800SecureRandomBuilder() {
        this(CryptoServicesRegistrar.getSecureRandom(), false);
    }
    
    public SP800SecureRandomBuilder(final SecureRandom random, final boolean b) {
        this.securityStrength = 256;
        this.entropyBitsRequired = 256;
        this.random = random;
        this.entropySourceProvider = new BasicEntropySourceProvider(this.random, b);
    }
    
    public SP800SecureRandomBuilder(final EntropySourceProvider entropySourceProvider) {
        this.securityStrength = 256;
        this.entropyBitsRequired = 256;
        this.random = null;
        this.entropySourceProvider = entropySourceProvider;
    }
    
    public SP800SecureRandomBuilder setPersonalizationString(final byte[] array) {
        this.personalizationString = Arrays.clone(array);
        return this;
    }
    
    public SP800SecureRandomBuilder setSecurityStrength(final int securityStrength) {
        this.securityStrength = securityStrength;
        return this;
    }
    
    public SP800SecureRandomBuilder setEntropyBitsRequired(final int entropyBitsRequired) {
        this.entropyBitsRequired = entropyBitsRequired;
        return this;
    }
    
    public SP800SecureRandom buildHash(final Digest digest, final byte[] array, final boolean b) {
        return new SP800SecureRandom(this.random, this.entropySourceProvider.get(this.entropyBitsRequired), new HashDRBGProvider(digest, array, this.personalizationString, this.securityStrength), b);
    }
    
    public SP800SecureRandom buildCTR(final BlockCipher blockCipher, final int n, final byte[] array, final boolean b) {
        return new SP800SecureRandom(this.random, this.entropySourceProvider.get(this.entropyBitsRequired), new CTRDRBGProvider(blockCipher, n, array, this.personalizationString, this.securityStrength), b);
    }
    
    public SP800SecureRandom buildHMAC(final Mac mac, final byte[] array, final boolean b) {
        return new SP800SecureRandom(this.random, this.entropySourceProvider.get(this.entropyBitsRequired), new HMacDRBGProvider(mac, array, this.personalizationString, this.securityStrength), b);
    }
    
    private static String getSimplifiedName(final Digest digest) {
        final String algorithmName = digest.getAlgorithmName();
        final int index = algorithmName.indexOf(45);
        if (index > 0 && !algorithmName.startsWith("SHA3")) {
            return algorithmName.substring(0, index) + algorithmName.substring(index + 1);
        }
        return algorithmName;
    }
    
    private static class CTRDRBGProvider implements DRBGProvider
    {
        private final BlockCipher blockCipher;
        private final int keySizeInBits;
        private final byte[] nonce;
        private final byte[] personalizationString;
        private final int securityStrength;
        
        public CTRDRBGProvider(final BlockCipher blockCipher, final int keySizeInBits, final byte[] nonce, final byte[] personalizationString, final int securityStrength) {
            this.blockCipher = blockCipher;
            this.keySizeInBits = keySizeInBits;
            this.nonce = nonce;
            this.personalizationString = personalizationString;
            this.securityStrength = securityStrength;
        }
        
        @Override
        public String getAlgorithm() {
            if (this.blockCipher instanceof DESedeEngine) {
                return "CTR-DRBG-3KEY-TDES";
            }
            return "CTR-DRBG-" + this.blockCipher.getAlgorithmName() + this.keySizeInBits;
        }
        
        @Override
        public SP80090DRBG get(final EntropySource entropySource) {
            return new CTRSP800DRBG(this.blockCipher, this.keySizeInBits, this.securityStrength, entropySource, this.personalizationString, this.nonce);
        }
    }
    
    private static class HMacDRBGProvider implements DRBGProvider
    {
        private final Mac hMac;
        private final byte[] nonce;
        private final byte[] personalizationString;
        private final int securityStrength;
        
        public HMacDRBGProvider(final Mac hMac, final byte[] nonce, final byte[] personalizationString, final int securityStrength) {
            this.hMac = hMac;
            this.nonce = nonce;
            this.personalizationString = personalizationString;
            this.securityStrength = securityStrength;
        }
        
        @Override
        public String getAlgorithm() {
            if (this.hMac instanceof HMac) {
                return "HMAC-DRBG-" + getSimplifiedName(((HMac)this.hMac).getUnderlyingDigest());
            }
            return "HMAC-DRBG-" + this.hMac.getAlgorithmName();
        }
        
        @Override
        public SP80090DRBG get(final EntropySource entropySource) {
            return new HMacSP800DRBG(this.hMac, this.securityStrength, entropySource, this.personalizationString, this.nonce);
        }
    }
    
    private static class HashDRBGProvider implements DRBGProvider
    {
        private final Digest digest;
        private final byte[] nonce;
        private final byte[] personalizationString;
        private final int securityStrength;
        
        public HashDRBGProvider(final Digest digest, final byte[] nonce, final byte[] personalizationString, final int securityStrength) {
            this.digest = digest;
            this.nonce = nonce;
            this.personalizationString = personalizationString;
            this.securityStrength = securityStrength;
        }
        
        @Override
        public String getAlgorithm() {
            return "HASH-DRBG-" + getSimplifiedName(this.digest);
        }
        
        @Override
        public SP80090DRBG get(final EntropySource entropySource) {
            return new HashSP800DRBG(this.digest, this.securityStrength, entropySource, this.personalizationString, this.nonce);
        }
    }
}
