simpleserver.stream.Encryption.java Source code

Java tutorial

Introduction

Here is the source code for simpleserver.stream.Encryption.java

Source

/*
 * Copyright (c) 2010 SimpleServer authors (see CONTRIBUTORS)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package simpleserver.stream;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.io.CipherInputStream;
import org.bouncycastle.crypto.io.CipherOutputStream;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;

public abstract class Encryption {
    protected SecretKey sharedKey;
    protected byte[] challengeToken;

    public static class ServerEncryption extends Encryption {
        private PublicKey publicKey;

        public ServerEncryption() {
            try {
                sharedKey = generateSharedKey();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }

        public byte[] getEncryptedSharedKey() {
            try {
                return encrypt(publicKey, sharedKey.getEncoded(), 1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        public void setPublicKey(byte[] keyBytes) {
            try {
                publicKey = getPublicKey(keyBytes);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public byte[] encryptChallengeToken() {
            try {
                return encrypt(publicKey, challengeToken, 1);
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    public static class ClientEncryption extends Encryption {
        private static KeyPair keyPair;

        public static void generateKeyPair() throws NoSuchAlgorithmException {
            KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
            keyGenerator.initialize(1024);
            keyPair = keyGenerator.generateKeyPair();
        }

        public void setEncryptedSharedKey(byte[] encryptedSharedKey) {
            try {
                sharedKey = decryptSharedKey(encryptedSharedKey, keyPair.getPrivate());
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            }
        }

        public String getLoginHash(String name) throws NoSuchAlgorithmException, UnsupportedEncodingException {
            return new BigInteger(loginHash(name, keyPair.getPublic(), sharedKey)).toString(16);
        }

        public byte[] getPublicKey() {
            return keyPair.getPublic().getEncoded();
        }

        public boolean checkChallengeToken(byte[] challengeTokenResponse) {
            try {
                return Arrays.equals(encrypt(keyPair.getPrivate(), challengeTokenResponse, 2), challengeToken);
            } catch (GeneralSecurityException e) {
                return false;
            }
        }
    }

    public BufferedBlockCipher getStreamCipher(boolean out) {
        BufferedBlockCipher cipher = new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 8));
        cipher.init(out,
                new ParametersWithIV(new KeyParameter(sharedKey.getEncoded()), sharedKey.getEncoded(), 0, 16));
        return cipher;
    }

    public OutputStream encryptedOutputStream(OutputStream stream) {
        try {
            return new CipherOutputStream(stream, getStreamCipher(true));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public InputStream encryptedInputStream(InputStream stream) {
        try {
            return new CipherInputStream(stream, getStreamCipher(false));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void setChallengeToken(byte[] challangeToken) {
        challengeToken = challangeToken;
    }

    private static PublicKey getPublicKey(byte[] keyBytes) throws GeneralSecurityException {
        return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyBytes));
    }

    private static SecretKey generateSharedKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128);
        return keyGenerator.generateKey();
    }

    private static byte[] loginHash(String name, PublicKey publicKey, SecretKey sharedKey)
            throws NoSuchAlgorithmException, UnsupportedEncodingException {
        return getHash("SHA-1",
                new byte[][] { name.getBytes("ISO_8859_1"), sharedKey.getEncoded(), publicKey.getEncoded() });
    }

    private static byte[] getHash(String algrithm, byte[][] data) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance(algrithm);
        for (byte[] bytes : data) {
            digest.update(bytes);
        }
        return digest.digest();
    }

    private static Cipher getCipher(String transformation, Key key, int mode) throws GeneralSecurityException {
        Cipher cipher;
        cipher = Cipher.getInstance(transformation);
        cipher.init(mode, key);
        return cipher;
    }

    private static byte[] encrypt(Key key, byte[] data, int opmode) throws GeneralSecurityException {
        return getCipher(key.getAlgorithm(), key, opmode).doFinal(data);
    }

    private static SecretKey decryptSharedKey(byte[] encryptedKey, PrivateKey privateKey)
            throws GeneralSecurityException {
        return new SecretKeySpec(encrypt(privateKey, encryptedKey, 2), "RC4");
    }

}