Java使用RSA通过套接字从客户端发送加密文本并在服务器中解密

时间:2018-02-22 23:46:41

标签: java rsa

我一直在尝试在一个非常简单的客户端 - 服务器Java应用程序中实现RSA加密。

为了尝试了解加密的工作原理,我制作了自己的方案:

  1. Alice(服务器)想要向Bob(客户端)发送消息。
  2. 当Bob连接到Alice时,他们交换公钥(e,n)。
  3. 一旦他们交换了公钥,Alice会加密消息“你好!”使用Bob的公钥并将其发送给Bob。
  4. Bob收到加密邮件并使用其私钥(d,n)对其进行解密。
  5. 这对我来说都很有意义,但是当我尝试用Java实现它时,我得到了不一致的结果。有时我会得到NegativeArrayExceptionArithmeticException: BigInteger would overflow supported range,而我从未成功解密过字符串。

    这是我的实施:

    RSA.java

    import java.math.BigInteger;
    import java.security.SecureRandom;
    
    public class RSA {
        private BigInteger n;
        private BigInteger d;
        private BigInteger e;
    
        private PrivateKey privateKey;
        private PublicKey publicKey;
    
        public static class PublicKey {
            public byte[] getE() {
                return e;
            }
    
            public byte[] getN() {
                return n;
            }
    
            private final byte[] e;
            private final byte[] n;
    
            public PublicKey(byte[] e, byte[] n) {
                this.e = e;
                this.n = n;
            }
        }
    
        public static class PrivateKey {
            public byte[] getD() {
                return d;
            }
            public byte[] getN() {
                return n;
            }
            private final byte[] d;
            private final byte[] n;
    
            public PrivateKey(byte[] n, byte[] d) {
                this.n = n;
                this.d = d;
            }
        }
    
        public RSA() {
            generateKeyPair(1024);
        }
    
        public RSA(int bits) {
            generateKeyPair(bits);
        }
    
        public final void generateKeyPair(int bits) {
    
            SecureRandom random = new SecureRandom();
    
            BigInteger p = new BigInteger(bits/2, 100, random);
            BigInteger q = new BigInteger(bits/2, 100, random);
            BigInteger phi = (p.subtract(new BigInteger("1"))).multiply(q.subtract(new BigInteger("1")));
    
            n = p.multiply(q);
            e = new BigInteger("3");
    
    
            while (phi.gcd(e).intValue() > 1) {
                e = e.add(new BigInteger("2"));
            }
    
            System.out.println(e.toString());
            System.out.println(n.toString());
    
            d = e.modInverse(phi);
            publicKey = new PublicKey(e.toByteArray(), n.toByteArray());
            privateKey = new PrivateKey(d.toByteArray(), n.toByteArray());
        }
    
    
        public byte[] encrypt(byte[] plainData, PublicKey publicKey) {
            return ((new BigInteger(plainData)).modPow(new BigInteger(publicKey.getE()), new BigInteger(publicKey.getN()))).toByteArray();
        }
    
        public byte[] decrypt(byte[] encryptedData) {
            return ((new BigInteger(encryptedData)).modPow(d, n)).toByteArray();
        }
    
        // (d, n)
        public PrivateKey getPrivateKey() {
            return privateKey;
        }
    
        // (e, n)
        public PublicKey getPublicKey() {
            return publicKey;
        }
    }
    

    Alice.java

    import crypto.RSA.PublicKey;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Alice {
        private final RSA encryption;
        public Alice() {
            encryption = new RSA();
    
            try {
                ServerSocket alice = new ServerSocket(2424);
    
                while(true) {
                    Socket bob = alice.accept();
    
                    DataInputStream inputStream = new DataInputStream(bob.getInputStream());
                    DataOutputStream outputStream = new DataOutputStream(bob.getOutputStream());
    
                    byte[] bobE = new byte[1];
                    byte[] bobN = new byte[inputStream.readInt()];
    
                    // Read Bob's Public Key to encrypt Alice's Message.
                    inputStream.read(bobE);
                    inputStream.read(bobN);
    
                    PublicKey bobPublicKey = new PublicKey(bobE, bobN);
    
                    byte[] aliceE = encryption.getPublicKey().getE();
                    byte[] aliceN = encryption.getPublicKey().getN();
    
                    // Send Alice's Public Key to Bob just in case he wants to send Alice a message.
                    outputStream.writeInt(aliceN.length); // N length
                    outputStream.write(aliceE, 0, aliceE.length);
                    outputStream.write(aliceN, 0, aliceN.length);   
    
                    outputStream.flush();
    
                    String messageToBob = "Hello!";
    
                    byte[] encryptedMessage = encryption.encrypt(messageToBob.getBytes(), bobPublicKey);
    
                    outputStream.writeInt(encryptedMessage.length);
                    outputStream.write(encryptedMessage, 1, encryptedMessage.length-1);
    
                    outputStream.flush();
                }
    
            } catch (IOException ex) {}
        }
    }
    

    Bob.java

    import crypto.RSA.PublicKey;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.Socket;
    
    public class Bob {
        private final RSA encryption;
        public Bob() {
            encryption = new RSA();
    
            try {
                Socket alice = new Socket("127.0.0.1", 2424);
    
                DataInputStream inputStream = new DataInputStream(alice.getInputStream());
                DataOutputStream outputStream = new DataOutputStream(alice.getOutputStream());
    
                // Send Bob's public E and N to Alice.
                byte[] bobE = encryption.getPublicKey().getE();
                byte[] bobN = encryption.getPublicKey().getN();
    
                outputStream.writeInt(bobN.length); // N length
                outputStream.write(bobE, 0, bobE.length);
                outputStream.write(bobN, 0, bobN.length);
                outputStream.flush();
    
                byte[] aliceE = new byte[1];
                byte[] aliceN = new byte[inputStream.readInt()];
    
                // Read Alice's public key. (unused)
                inputStream.read(aliceE);
                inputStream.read(aliceN);
    
                PublicKey alicePublicKey = new PublicKey(aliceE, aliceN);
    
                // Read Alice's Message Size.
                int encryptedMessageSize = inputStream.readInt();
    
                byte[] encryptedMessageFromAlice = new byte[encryptedMessageSize];
    
                // Read Alice's Message.
                // Here is where everything goes wrong.
                inputStream.read(encryptedMessageFromAlice, 1, encryptedMessageSize-1);
    
                System.out.println("Got a message from alice (" + encryptedMessageFromAlice.length + "): ");
                System.out.println(new String(encryption.decrypt(encryptedMessageFromAlice)));
    
            } catch (IOException ex) {}
        }
    }
    

    主要方法

    (new Thread() {
        @Override
        public void run() {
            Alice alice = new Alice();
    
        }
    }).start();
    
    Bob bob = new Bob();
    

    我觉得我可能会遗漏一些基础知识,但我已经阅读了它是如何工作的,检查了一些例子(尽管这些例子都不完整),但我看不出错误在哪里。

    我知道有些库可以让这更容易,但是我需要使用BigInteger来学习它的基本实现。

    任何帮助和指导将不胜感激。谢谢!

    更新1: 詹姆斯说,我已经将模数的长度设为非硬编码。

    运行程序后,这里打印出来的内容(消息总是相同的“Hello!”):

    尝试1

    Got a message from alice (41): 
    N�qpfcc�d�����J��
    �$P�m�1�qj?��K�����s�����IQ@��g�u�)^���\m"ݒ�M��7p�}�!����
    

    尝试2

    Got a message from alice (41): 
    W��LW\t� b�w��P�3Ꟊ��?�g��ϔSx�N���<Vx� �ĝJ:h1��ޟ�KY�:vtad��0\R-�ǰ���3D4~_�
    ~���Cy�$$y��#{�^U$;՞�RU��ݘN�C'0��S
    

    尝试3

    Got a message from alice (18): 
    Rq���ҞlapZ�L����t�,��@k��&��=�.o�� ��   ��������؉I�g>+h��ʸz��=��l���a��+�\Gഢ��ccn�n�1[1���Bu�A�]    �n�b�Tu�o!
    

0 个答案:

没有答案