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

package com.google.crypto.tink.jwt;

import com.google.gson.JsonObject;
import com.google.crypto.tink.jwt.internal.JsonUtil;
import java.nio.charset.StandardCharsets;
import com.google.crypto.tink.Mac;
import com.google.errorprone.annotations.Immutable;
import com.google.protobuf.MessageLite;
import com.google.protobuf.Parser;
import com.google.crypto.tink.internal.LegacyKeyManagerImpl;
import com.google.crypto.tink.proto.KeyData;
import com.google.crypto.tink.internal.TinkBugException;
import com.google.crypto.tink.KeyTemplate;
import com.google.crypto.tink.internal.KeyManagerRegistry;
import com.google.crypto.tink.internal.MutableParametersRegistry;
import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
import com.google.crypto.tink.internal.MutableKeyCreationRegistry;
import java.util.Collections;
import java.util.HashMap;
import com.google.crypto.tink.Parameters;
import java.util.Map;
import com.google.crypto.tink.util.SecretBytes;
import javax.annotation.Nullable;
import com.google.crypto.tink.AccessesPartialKey;
import com.google.crypto.tink.subtle.PrfMac;
import com.google.crypto.tink.mac.HmacKey;
import com.google.crypto.tink.mac.HmacParameters;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.config.internal.TinkFipsUtil;
import com.google.crypto.tink.internal.KeyCreator;
import com.google.crypto.tink.internal.PrimitiveConstructor;
import com.google.crypto.tink.KeyManager;

public final class JwtHmacKeyManager
{
    private static final KeyManager<Void> legacyKeyManager;
    private static final PrimitiveConstructor<JwtHmacKey, JwtMac> PRIMITIVE_CONSTRUCTOR;
    private static final KeyCreator<JwtHmacParameters> KEY_CREATOR;
    private static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS;
    
    private static void validate(final JwtHmacParameters parameters) throws GeneralSecurityException {
        int minKeySize = Integer.MAX_VALUE;
        if (parameters.getAlgorithm().equals(JwtHmacParameters.Algorithm.HS256)) {
            minKeySize = 32;
        }
        if (parameters.getAlgorithm().equals(JwtHmacParameters.Algorithm.HS384)) {
            minKeySize = 48;
        }
        if (parameters.getAlgorithm().equals(JwtHmacParameters.Algorithm.HS512)) {
            minKeySize = 64;
        }
        if (parameters.getKeySizeBytes() < minKeySize) {
            throw new GeneralSecurityException("Key size must be at least " + minKeySize);
        }
    }
    
    private static int getTagLength(final JwtHmacParameters.Algorithm algorithm) throws GeneralSecurityException {
        if (algorithm.equals(JwtHmacParameters.Algorithm.HS256)) {
            return 32;
        }
        if (algorithm.equals(JwtHmacParameters.Algorithm.HS384)) {
            return 48;
        }
        if (algorithm.equals(JwtHmacParameters.Algorithm.HS512)) {
            return 64;
        }
        throw new GeneralSecurityException("Unsupported algorithm: " + algorithm);
    }
    
    private static HmacParameters.HashType getHmacHashType(final JwtHmacParameters.Algorithm algorithm) throws GeneralSecurityException {
        if (algorithm.equals(JwtHmacParameters.Algorithm.HS256)) {
            return HmacParameters.HashType.SHA256;
        }
        if (algorithm.equals(JwtHmacParameters.Algorithm.HS384)) {
            return HmacParameters.HashType.SHA384;
        }
        if (algorithm.equals(JwtHmacParameters.Algorithm.HS512)) {
            return HmacParameters.HashType.SHA512;
        }
        throw new GeneralSecurityException("Unsupported algorithm: " + algorithm);
    }
    
    @AccessesPartialKey
    private static JwtMac createFullJwtHmac(final JwtHmacKey key) throws GeneralSecurityException {
        validate(key.getParameters());
        final HmacKey hmacKey = HmacKey.builder().setParameters(HmacParameters.builder().setKeySizeBytes(key.getParameters().getKeySizeBytes()).setHashType(getHmacHashType(key.getParameters().getAlgorithm())).setTagSizeBytes(getTagLength(key.getParameters().getAlgorithm())).build()).setKeyBytes(key.getKeyBytes()).build();
        return new JwtHmac(PrfMac.create(hmacKey), key);
    }
    
    static String getKeyType() {
        return "type.googleapis.com/google.crypto.tink.JwtHmacKey";
    }
    
    @AccessesPartialKey
    private static JwtHmacKey createKey(final JwtHmacParameters parameters, @Nullable final Integer idRequirement) throws GeneralSecurityException {
        validate(parameters);
        final JwtHmacKey.Builder builder = JwtHmacKey.builder().setParameters(parameters).setKeyBytes(SecretBytes.randomBytes(parameters.getKeySizeBytes()));
        if (parameters.hasIdRequirement()) {
            if (idRequirement == null) {
                throw new GeneralSecurityException("Cannot create key without ID requirement with parameters with ID requirement");
            }
            builder.setIdRequirement(idRequirement);
        }
        return builder.build();
    }
    
    private static Map<String, Parameters> namedParameters() throws GeneralSecurityException {
        final Map<String, Parameters> result = new HashMap<String, Parameters>();
        result.put("JWT_HS256_RAW", JwtHmacParameters.builder().setKeySizeBytes(32).setAlgorithm(JwtHmacParameters.Algorithm.HS256).setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED).build());
        result.put("JWT_HS256", JwtHmacParameters.builder().setKeySizeBytes(32).setAlgorithm(JwtHmacParameters.Algorithm.HS256).setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID).build());
        result.put("JWT_HS384_RAW", JwtHmacParameters.builder().setKeySizeBytes(48).setAlgorithm(JwtHmacParameters.Algorithm.HS384).setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED).build());
        result.put("JWT_HS384", JwtHmacParameters.builder().setKeySizeBytes(48).setAlgorithm(JwtHmacParameters.Algorithm.HS384).setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID).build());
        result.put("JWT_HS512_RAW", JwtHmacParameters.builder().setKeySizeBytes(64).setAlgorithm(JwtHmacParameters.Algorithm.HS512).setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED).build());
        result.put("JWT_HS512", JwtHmacParameters.builder().setKeySizeBytes(64).setAlgorithm(JwtHmacParameters.Algorithm.HS512).setKidStrategy(JwtHmacParameters.KidStrategy.BASE64_ENCODED_KEY_ID).build());
        return Collections.unmodifiableMap((Map<? extends String, ? extends Parameters>)result);
    }
    
    public TinkFipsUtil.AlgorithmFipsCompatibility fipsStatus() {
        return JwtHmacKeyManager.FIPS;
    }
    
    public static void register(final boolean newKeyAllowed) throws GeneralSecurityException {
        if (!JwtHmacKeyManager.FIPS.isCompatible()) {
            throw new GeneralSecurityException("Can not use HMAC in FIPS-mode, as BoringCrypto module is not available.");
        }
        JwtHmacProtoSerialization.register();
        MutableKeyCreationRegistry.globalInstance().add(JwtHmacKeyManager.KEY_CREATOR, JwtHmacParameters.class);
        MutablePrimitiveRegistry.globalInstance().registerPrimitiveConstructor(JwtHmacKeyManager.PRIMITIVE_CONSTRUCTOR);
        MutableParametersRegistry.globalInstance().putAll(namedParameters());
        KeyManagerRegistry.globalInstance().registerKeyManagerWithFipsCompatibility(JwtHmacKeyManager.legacyKeyManager, JwtHmacKeyManager.FIPS, newKeyAllowed);
    }
    
    public static final KeyTemplate hs256Template() {
        return TinkBugException.exceptionIsBug(() -> KeyTemplate.createFrom(JwtHmacParameters.builder().setKeySizeBytes(32).setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED).setAlgorithm(JwtHmacParameters.Algorithm.HS256).build()));
    }
    
    public static final KeyTemplate hs384Template() {
        return TinkBugException.exceptionIsBug(() -> KeyTemplate.createFrom(JwtHmacParameters.builder().setKeySizeBytes(48).setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED).setAlgorithm(JwtHmacParameters.Algorithm.HS384).build()));
    }
    
    public static final KeyTemplate hs512Template() {
        return TinkBugException.exceptionIsBug(() -> KeyTemplate.createFrom(JwtHmacParameters.builder().setKeySizeBytes(64).setKidStrategy(JwtHmacParameters.KidStrategy.IGNORED).setAlgorithm(JwtHmacParameters.Algorithm.HS512).build()));
    }
    
    private JwtHmacKeyManager() {
    }
    
    static {
        legacyKeyManager = LegacyKeyManagerImpl.create("type.googleapis.com/google.crypto.tink.JwtHmacKey", Void.class, KeyData.KeyMaterialType.SYMMETRIC, com.google.crypto.tink.proto.JwtHmacKey.parser());
        PRIMITIVE_CONSTRUCTOR = PrimitiveConstructor.create(JwtHmacKeyManager::createFullJwtHmac, JwtHmacKey.class, JwtMac.class);
        KEY_CREATOR = JwtHmacKeyManager::createKey;
        FIPS = TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_REQUIRES_BORINGCRYPTO;
    }
    
    @Immutable
    private static final class JwtHmac implements JwtMac
    {
        private final Mac mac;
        private final String algorithm;
        private final JwtHmacKey jwtHmacKey;
        
        private JwtHmac(final Mac plainMac, final JwtHmacKey jwtHmacKey) {
            this.algorithm = jwtHmacKey.getParameters().getAlgorithm().getStandardName();
            this.mac = plainMac;
            this.jwtHmacKey = jwtHmacKey;
        }
        
        @Override
        public String computeMacAndEncode(final RawJwt rawJwt) throws GeneralSecurityException {
            final String unsignedCompact = JwtFormat.createUnsignedCompact(this.algorithm, this.jwtHmacKey.getKid(), rawJwt);
            return JwtFormat.createSignedCompact(unsignedCompact, this.mac.computeMac(unsignedCompact.getBytes(StandardCharsets.US_ASCII)));
        }
        
        @Override
        public VerifiedJwt verifyMacAndDecode(final String compact, final JwtValidator validator) throws GeneralSecurityException {
            final JwtFormat.Parts parts = JwtFormat.splitSignedCompact(compact);
            this.mac.verifyMac(parts.signatureOrMac, parts.unsignedCompact.getBytes(StandardCharsets.US_ASCII));
            final JsonObject parsedHeader = JsonUtil.parseJson(parts.header);
            JwtFormat.validateHeader(parsedHeader, this.jwtHmacKey.getParameters().getAlgorithm().getStandardName(), this.jwtHmacKey.getKid(), this.jwtHmacKey.getParameters().allowKidAbsent());
            final RawJwt token = RawJwt.fromJsonPayload(JwtFormat.getTypeHeader(parsedHeader), parts.payload);
            return validator.validate(token);
        }
    }
}
