Package io.fathom.cloud.openstack.client.identity

Source Code of io.fathom.cloud.openstack.client.identity.ChallengeResponses

package io.fathom.cloud.openstack.client.identity;

import io.fathom.cloud.openstack.client.identity.model.V2AuthRequest;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.security.auth.x500.X500Principal;

import com.fathomdb.crypto.CertificateAndKey;
import com.fathomdb.crypto.SimpleCertificateAndKey;
import com.fathomdb.crypto.bouncycastle.SimpleCertificateAuthority;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.google.common.io.BaseEncoding;
import com.google.common.primitives.Bytes;

public class ChallengeResponses {

    private static final byte[] PREFIX_V1_BYTES = "openstack-rsa-v1".getBytes(Charsets.UTF_8);

    public static boolean hasPrefix(byte[] data) {
        if (data.length < PREFIX_V1_BYTES.length) {
            return false;
        }
        byte[] head = new byte[PREFIX_V1_BYTES.length];
        System.arraycopy(data, 0, head, 0, PREFIX_V1_BYTES.length);
        return Arrays.equals(head, PREFIX_V1_BYTES);
    }

    public static byte[] getPayload(byte[] data) {
        if (!hasPrefix(data)) {
            throw new IllegalArgumentException();
        }
        byte[] tail = new byte[data.length - PREFIX_V1_BYTES.length];
        System.arraycopy(data, PREFIX_V1_BYTES.length, tail, 0, tail.length);
        return tail;
    }

    public static byte[] addHeader(byte[] ciphertext) {
        return Bytes.concat(PREFIX_V1_BYTES, ciphertext);
    }

    public static V2AuthRequest.ChallengeResponse respondToAuthChallenge(CertificateAndKey certificateAndKey,
            String challenge) {
        if (Strings.isNullOrEmpty(challenge)) {
            throw new IllegalStateException("Did not receieve challenge when authenticating");
        }

        byte[] challengeBytes = BaseEncoding.base64().decode(challenge);

        // The prefix acts as a version
        if (!hasPrefix(challengeBytes)) {
            throw new IllegalStateException("Challenge was not in a recognized format");
        }

        byte[] ciphertext = getPayload(challengeBytes);
        byte[] plaintext = decrypt(certificateAndKey.getPrivateKey(), ciphertext);

        // The prefix must also be in the plaintext
        if (!hasPrefix(plaintext)) {
            throw new IllegalStateException("Challenge was not valid (bad decrypted result)");
        }

        V2AuthRequest.ChallengeResponse challengeResponse = new V2AuthRequest.ChallengeResponse();
        challengeResponse.challenge = challenge;
        challengeResponse.response = BaseEncoding.base64().encode(plaintext);

        return challengeResponse;
    }

    public static V2AuthRequest.ChallengeResponse respondToRegistrationChallenge(CertificateAndKey certificateAndKey,
            String challenge) {
        if (Strings.isNullOrEmpty(challenge)) {
            throw new IllegalStateException("Did not receieve challenge when authenticating");
        }

        byte[] challengeBytes = BaseEncoding.base64().decode(challenge);

        // The prefix acts as a version
        if (!hasPrefix(challengeBytes)) {
            throw new IllegalStateException("Challenge was not in a recognized format");
        }

        // The payload is no longer encrypted, because the server doesn't get
        // the public key behind a firewall
        byte[] payload = getPayload(challengeBytes);

        // The prefix must also be in the payload
        if (!hasPrefix(payload)) {
            throw new IllegalStateException("Challenge was not valid");
        }

        byte[] plaintext = encrypt(certificateAndKey.getPublicKey(), payload);

        V2AuthRequest.ChallengeResponse challengeResponse = new V2AuthRequest.ChallengeResponse();
        challengeResponse.challenge = challenge;
        challengeResponse.response = BaseEncoding.base64().encode(plaintext);

        return challengeResponse;
    }

    public static byte[] encrypt(Key key, byte[] plaintext) {
        Cipher cipher = getCipher(key);

        try {
            cipher.init(Cipher.ENCRYPT_MODE, key);
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException("Invalid key", e);
        }

        byte[] ciphertext;
        try {
            ciphertext = cipher.doFinal(plaintext);
        } catch (IllegalBlockSizeException e) {
            throw new IllegalArgumentException("Error in encryption", e);
        } catch (BadPaddingException e) {
            throw new IllegalArgumentException("Error in encryption", e);
        }
        return ciphertext;
    }

    private static Cipher getCipher(Key key) {
        Cipher cipher;

        String algorithm = "RSA";
        try {
            cipher = Cipher.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("Error loading crypto provider", e);
        } catch (NoSuchPaddingException e) {
            throw new IllegalArgumentException("Error loading crypto provider", e);
        }
        return cipher;
    }

    static byte[] decrypt(Key key, byte[] ciphertext) {
        Cipher cipher = getCipher(key);

        try {
            cipher.init(Cipher.DECRYPT_MODE, key);
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException("Invalid key", e);
        }

        byte[] plaintext;
        try {
            plaintext = cipher.doFinal(ciphertext);
        } catch (IllegalBlockSizeException e) {
            throw new IllegalArgumentException("Error in encryption", e);
        } catch (BadPaddingException e) {
            throw new IllegalArgumentException("Error in encryption", e);
        }
        return plaintext;
    }

    public static CertificateAndKey createSelfSigned(X500Principal principal, KeyPair keypair) {
        X500Principal subject = principal;
        PublicKey subjectPublicKey = keypair.getPublic();
        X500Principal issuer = principal;
        PrivateKey issuerPrivateKey = keypair.getPrivate();
        X509Certificate certificate = SimpleCertificateAuthority.signAsCa(subject, subjectPublicKey, issuer,
                issuerPrivateKey);

        X509Certificate[] certificateChain = new X509Certificate[1];
        certificateChain[0] = certificate;

        return new SimpleCertificateAndKey(certificateChain, keypair.getPrivate());
    }

}
TOP

Related Classes of io.fathom.cloud.openstack.client.identity.ChallengeResponses

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.