Java中的电话到服务器通信加密 [英] Phone-To-Server communication encryption in Java

查看:117
本文介绍了Java中的电话到服务器通信加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这与另一个线程一起出现在这里:
如何使用CBC实现Java 256位AES加密



主要是尝试使用Java在手机上获取AES加密。 >

我的问题是如何处理加密密钥。我不知道我是否应该存储密钥,哈希密钥并使用它,或做一个公钥密钥方案。我宁愿有办法不做一个从服务器到手机的初始消息来传递一个密钥。我想要手机准备加密,服务器等待加密的消息。要实现类似密钥共享算法的东西,我将不得不修改我们不太可取的服务器应用程序。这不是不可能的,但我要在这里使用代码重用=)。

解决方案

你是否试图找到一种方法在每个电话上存储相同的密钥,但是防止任何攻击者获取密钥并做坏事?这是不可能的。



估计如果密钥被披露可能花费多少钱。然后估计理解的成本,并实现类似以下密钥协商方案。选择最适合您目标的替代方案。



使用临时–静态Diffie-Hellman密钥协议。为了拦截流量,攻击者必须窃取一个特定的手机,并用自己的手机替换嵌入在应用程序中的服务器的公钥。这是非常有挑战性的,每个用户必须单独定位,所以攻击不能很好地扩展。



RSA加密也可以工作。它是安全和广泛的支持。但短暂的Diffie-Hellman有一个优势。 RSA将依靠一个固定的密钥对,所以如果一个攻击者最终恢复了私有密钥,那么她可以解密任何以前记录的消息。



由于这两种算法的速度应该是可比的,所以建议使用Diffie-Hellman,除非手机不支持。这是一个例子。 (对于长度过长,我很抱歉)

  import java.math.BigInteger; 
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DHExample
{

public static void main(String ... argv)
throws异常
{
if(argv.length == 0)
argv = new String [] {swright,password,transfer(10000USD,erickson)};

/ *实际上,私钥应该存储在KeyStore中,由
*保护,每当服务器
*启动时,交互式提供强密码。
* /
PrivateKey pvt = Server.loadDemoKey();
服务器服务器=新服务器(pvt);

(String message:argv){
客户端客户端=新建Client();
byte [] packet = client.encrypt(message);
/ *客户端(电话)然后将数据包发送到服务器... * /
/ * ...现在,在服务器上:* /
System.out.println (server.decrypt(分组));
}

}

}

类客户
{

/ *此公开键对应于服务器使用的私钥。
*生成您自己的Diffie-Hellman密钥对,对公钥进行编码,并将
*嵌入到此处。
* /
私有静态最后弦乐服务器= 1GG80QCC4204DGC29AGP48DTOD041G2C42046050C103UNUKS13LQH4AAIRT59OBNCSJJVC4DNA8UEUH00OCF3V05MA4J6IHAT80H53UQP7M6LHULVONQRKC7MPEDLAR6NG4TO079KDVP6CO5NDECL19D4JUFUG13R20HC4JTRL7BVTDU63FS3MLV7OQKAC58F0JTO7TMJOKFC60HLAG9LK5KH6BR7BSTE5DGTEANFU8H066CTQ5403HO2G60G1TV1K22TD6PTRR5RPAQS6QS5FEBPIINRNUHQTA1FILQC1CUGF0J7A5CLF3LQQHCKVPJH0S88305K94B728V89GK1C4TNPS4J5368KRGJO5JQHDA7P398S2HQS7HBMEJ7B4BEKDVGNUH16LHF3UR2F80I8EUCKJORTA2HI24QH0UVS5DEB7O6IA5MCNK0FDAIAP019GTVTJQ9581040G00E0O8002G600TNIVRQ4KUFKVHTM685L9LRNURUUJ8B1EC45DN5TM70MI0T8RM17QCBSQ2F1FMQM3K63MVVQBMVD7N5MRVMGRVM09B1LGNU92SMS42RSROH3FMP4532CMDHO6E72ICI7USNGGDHPFLTSS7AAFRM9T8E6ELU4E3P5EBA6JPDRUN0PDNG08HBVSRJM5U7VVAQ1PD8FIJMSN9EM3;

public byte [] encrypt(String message)
throws异常
{
/ *将嵌入式服务器公钥转换为DHPublickKey对象。 * /
KeyFactory kf = KeyFactory.getInstance(DiffieHellman);
byte [] decoded = new BigInteger(Client.server,32).toByteArray();
DHPublicKey server =(DHPublicKey)kf.generatePublic(新的X509EncodedKeySpec(解码));
/ *生成与服务器相同参数的短暂密钥对。 * /
KeyPairGenerator gen = KeyPairGenerator.getInstance(DiffieHellman);
gen.initialize(server.getParams());
KeyPair ephemeral = gen.generateKeyPair();
/ *编码使用密文发送到服务器的客户端公钥。 * /
byte [] pub = ephemeral.getPublic()。getEncoded();
/ *在客户端和服务器之间使用Diffie-Hellman生成密钥。 * /
KeyAgreement ka = KeyAgreement.getInstance(DiffieHellman);
ka.init(ephemeral.getPrivate());
ka.doPhase(server,true);
byte [] raw = ka.generateSecret();
SecretKeySpec秘密;
try {
secret = new SecretKeySpec(raw,0,16,AES);
}
finally {
Arrays.fill(raw,(byte)0);
}
/ *使用密钥设置加密密码。 * /
密码密码= Cipher.getInstance(AES / CBC / PKCS5Padding);
cipher.init(Cipher.ENCRYPT_MODE,secret);
/ *使用密文将IV发送到服务器。 * /
byte [] iv = cipher.getParameters()。getParameterSpec(IvParameterSpec.class).getIV();
/ *使用密钥加密邮件。 * /
byte [] plaintext = message.getBytes(UTF-8);
byte [] ciphertext;
try {
ciphertext = cipher.doFinal(plaintext);
}
finally {
Arrays.fill(plaintext,(byte)0);
}
/ *打包临时公钥,iv和密文传送到服务器。 * /
byte [] packet = new byte [4 + pub.length + iv.length + ciphertext.length]; (int idx = 0; idx <4; ++ idx)
packet [idx] =(byte)(pub.length>>>> 8 * idx)
System.arraycopy(pub,0,packet,4,pub.length);
System.arraycopy(iv,0,packet,4 + pub.length,iv.length);
System.arraycopy(ciphertext,0,packet,4 + pub.length + iv.length,ciphertext.length);
返回包;
}


}

类服务器
{

/ *此密钥不再是私有的,因为它发布在stackoverflow.com上。
*生成您自己的Diffie-Hellman密钥对,对私钥进行编码,并将
*嵌入到此处。在实际的代码中,您不会嵌入这样的私钥。这个
*只是为了启用演示。
* /
私有静态最后弦乐演示= 310G1CS10201GG80HM1G95A34H1NN1K0G609GG80GO0K1G40FQVQJG4ENA4H9ABFKL71ETJIEFTGHMT93PRQ4031HSFS0MP8ICQA5BL024KFRB4UOQM7QNV2VBEHGUR5PMLBCQU0JN00T6HNV4PJ0MTLPIK55KIFPVQ04FC825GIFNEKTFVLNOODVGEQNSV3AH9GL1S2FN0VMQF2HTGO26LA16MGMI4PFCTFJLOLM3LPATVP240OPJN8KG0E70A0O207NS6G8BLKR7NFCNF5BBGRBGLTPF6AAVEVQ7BL85UAN9G5JQ1S2CT8LILSENBA5IJV6E43H10C0MH4HCS93T162G5GJMV7GICKCP2JE2F0MFA5L8V4D53GA7BGU5EPQCTCHDQHNU2VQ44QM5SFRC9T0291RPIIF3FL8A688JA43RVGLLPCV0Q98MPIUG1TLA9B40563NVMF94L040G2002460I103FO2B2UAKGMNI68O6B43G31SRIBA2NGIV0BEUVD4A85NIC25AVUGP3AG6LJVFHPOJ4JQ3DJA0PFHA2V6E2U80HNHFDG157KP0NJLE7U;

private final PrivateKey pvt;

static PrivateKey loadDemoKey()
throws异常
{
/ *将嵌入式服务器公钥转换为PrivateKey对象。 * /
KeyFactory kf = KeyFactory.getInstance(DiffieHellman);
byte [] decoded = new BigInteger(Server.demo,32).toByteArray(); X-45454545 X-454545 X-454545 X-454545 X- 20045 X-454545 X-454545 X-454545 X- 20045 X- 20045 X- 20045 X-
}

服务器(PrivateKey pvt)
{
this.pvt = pvt;
}

public String decrypt(byte [] packet)
throws异常
{
/ *解构数据包。 * /
int len = 0; (int idx = 0; idx <4; ++ idx)
len | =((packet [idx]& 0xFF))< 8 * idx)
byte [] pub = new byte [len];
System.arraycopy(packet,4,pub,0,len); X-4545 X-4545 X-4545 X-45 X-454545 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045
PublicKey client = kf.generatePublic(new X509EncodedKeySpec(pub));
IvParameterSpec iv = new IvParameterSpec(packet,len + 4,16);
/ *执行密钥协商确定密钥。 * /
KeyAgreement ka = KeyAgreement.getInstance(DiffieHellman);
ka.init(pvt);
ka.doPhase(client,true);
byte [] raw = ka.generateSecret();
SecretKeySpec秘密; X-4545454545 X-454545 X- 20045 X-454545 X- 20045 X-454545 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X- 20045 X-新评新新新新新新新旗新新新新旗新新旗新新旗新新旗新新旗新新新200新新新新旗新新旗新新款:
}
/ *使用密钥设置密码进行解密。 * /
密码密码= Cipher.getInstance(AES / CBC / PKCS5Padding);新新新新旗新新新新旗新新旗新新旗200新新新新新旗新新旗200新新新新旗200新新新新名:
byte [] plaintext = cipher.doFinal(packet,len + 20,packet.length - (len + 20));
try {
return new String(plaintext,UTF-8);新评新新新新新新新新新旗新新旗新新旗200新新新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新
}
}

}


This goes along with another thread, here: How to implement Java 256-bit AES encryption with CBC

Mainly, trying to get AES encryption on a phone using Java.

My question here is how to handle the encryption key. I don't know if I should store the key, hash the key and use that, or do a public-key-encyption scheme. I would rather have a way to not do an initial message from the server to the phone to communicate a key. I want the phone to be ready to encrypt and the server waiting for an encrypted message. To implement something like a key-sharing algorithm, I would have to modify our server application which is not very desireable. It's not impossible, but I'm going for code-reuse here =).

解决方案

Are you trying to find a way to store the same key on every phone, yet prevent any attackers from getting the key and doing bad things with it? That's just not possible.

Estimate how much it could potentially cost if the key is disclosed. Then estimate the cost of understanding and implementing something like the following key agreement scheme. Choose the alternative that best serves your objectives.

Use ephemeral–static Diffie-Hellman key agreement. To intercept traffic, an attacker would have to hack a particular phone, and replace the server's public key, which is embedded in the application, with her own. That's pretty challenging, and each user has to be targeted individually, so the attack doesn't scale well.

RSA encryption would also work. It is secure and widely supported. But ephemeral Diffie-Hellman has one advantage. RSA would rely on a fixed key pair, so if an attacker eventually recovered the private key, she could decrypt any previously recorded messages.

Since the speed of the two algorithms should be comparable, I recommend Diffie-Hellman unless phones don't support it. Here's an example. (I'm sorry for the excessive length.)

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DHExample
{

  public static void main(String... argv)
    throws Exception
  {
    if (argv.length == 0)
      argv = new String[]{"swright,password,transfer(10000USD,erickson)"};

    /* In reality, the private key should be stored in a KeyStore, protected by 
     * a strong password that is provided interactively every time the server 
     * is started.
     */
    PrivateKey pvt = Server.loadDemoKey();
    Server server = new Server(pvt);

    for (String message : argv) {
      Client client = new Client();
      byte[] packet = client.encrypt(message);
      /* The client (phone) would then send the packet to the server... */
      /* ... Now, at the server: */
      System.out.println(server.decrypt(packet));
    }

  }

}

class Client
{

  /* This public key corresponds to the private key used by the server. 
   * Generate your own Diffie-Hellman key pair, encode the public key, and 
   * embed it here.
   */
  private static final String server = "1GG80QCC4204DGC29AGP48DTOD041G2C42046050C103UNUKS13LQH4AAIRT59OBNCSJJVC4DNA8UEUH00OCF3V05MA4J6IHAT80H53UQP7M6LHULVONQRKC7MPEDLAR6NG4TO079KDVP6CO5NDECL19D4JUFUG13R20HC4JTRL7BVTDU63FS3MLV7OQKAC58F0JTO7TMJOKFC60HLAG9LK5KH6BR7BSTE5DGTEANFU8H066CTQ5403HO2G60G1TV1K22TD6PTRR5RPAQS6QS5FEBPIINRNUHQTA1FILQC1CUGF0J7A5CLF3LQQHCKVPJH0S88305K94B728V89GK1C4TNPS4J5368KRGJO5JQHDA7P398S2HQS7HBMEJ7B4BEKDVGNUH16LHF3UR2F80I8EUCKJORTA2HI24QH0UVS5DEB7O6IA5MCNK0FDAIAP019GTVTJQ9581040G00E0O8002G600TNIVRQ4KUFKVHTM685L9LRNURUUJ8B1EC45DN5TM70MI0T8RM17QCBSQ2F1FMQM3K63MVVQBMVD7N5MRVMGRVM09B1LGNU92SMS42RSROH3FMP4532CMDHO6E72ICI7USNGGDHPFLTSS7AAFRM9T8E6ELU4E3P5EBA6JPDRUN0PDNG08HBVSRJM5U7VVAQ1PD8FIJMSN9EM3";

  public byte[] encrypt(String message)
    throws Exception
  {
    /* Convert the embedded server public key into a DHPublickKey object. */
    KeyFactory kf = KeyFactory.getInstance("DiffieHellman");
    byte[] decoded = new BigInteger(Client.server, 32).toByteArray();
    DHPublicKey server = (DHPublicKey) kf.generatePublic(new X509EncodedKeySpec(decoded));
    /* Generate an ephemeral key pair with the same parameters as server's. */
    KeyPairGenerator gen = KeyPairGenerator.getInstance("DiffieHellman");
    gen.initialize(server.getParams());
    KeyPair ephemeral = gen.generateKeyPair();
    /* Encode the client public key to be sent to server with ciphertext. */
    byte[] pub = ephemeral.getPublic().getEncoded();
    /* Generate a secret key using Diffie-Hellman between client and server. */
    KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman");
    ka.init(ephemeral.getPrivate());
    ka.doPhase(server, true);
    byte[] raw = ka.generateSecret();
    SecretKeySpec secret;
    try {
      secret = new SecretKeySpec(raw, 0, 16, "AES");
    }
    finally {
      Arrays.fill(raw, (byte) 0);
    }
    /* Setup cipher for encryption with secret key. */
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    /* Get the IV to be sent to server with ciphertext. */
    byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
    /* Encrypt the message with the secret key. */
    byte[] plaintext = message.getBytes("UTF-8");
    byte[] ciphertext;
    try {
      ciphertext = cipher.doFinal(plaintext);
    }
    finally {
      Arrays.fill(plaintext, (byte) 0);
    }
    /* Package up ephemeral public key, iv, and cipher text to transmit to server. */
    byte[] packet = new byte[4 + pub.length + iv.length + ciphertext.length];
    for (int idx = 0; idx < 4; ++idx)
      packet[idx] = (byte) (pub.length >>> 8 * idx);
    System.arraycopy(pub, 0, packet, 4, pub.length);
    System.arraycopy(iv, 0, packet, 4 + pub.length, iv.length);
    System.arraycopy(ciphertext, 0, packet, 4 + pub.length + iv.length, ciphertext.length);
    return packet;
  }


}

class Server
{

  /* This key isn't private anymore, since it was posted on stackoverflow.com.
   * Generate your own Diffie-Hellman key pair, encode the private key, and 
   * embed it here. In real code, you don't embed private keys like this. This 
   * is just to enable the demonstration.
   */
  private static final String demo = "310G1CS10201GG80HM1G95A34H1NN1K0G609GG80GO0K1G40FQVQJG4ENA4H9ABFKL71ETJIEFTGHMT93PRQ4031HSFS0MP8ICQA5BL024KFRB4UOQM7QNV2VBEHGUR5PMLBCQU0JN00T6HNV4PJ0MTLPIK55KIFPVQ04FC825GIFNEKTFVLNOODVGEQNSV3AH9GL1S2FN0VMQF2HTGO26LA16MGMI4PFCTFJLOLM3LPATVP240OPJN8KG0E70A0O207NS6G8BLKR7NFCNF5BBGRBGLTPF6AAVEVQ7BL85UAN9G5JQ1S2CT8LILSENBA5IJV6E43H10C0MH4HCS93T162G5GJMV7GICKCP2JE2F0MFA5L8V4D53GA7BGU5EPQCTCHDQHNU2VQ44QM5SFRC9T0291RPIIF3FL8A688JA43RVGLLPCV0Q98MPIUG1TLA9B40563NVMF94L040G2002460I103FO2B2UAKGMNI68O6B43G31SRIBA2NGIV0BEUVD4A85NIC25AVUGP3AG6LJVFHPOJ4JQ3DJA0PFHA2V6E2U80HNHFDG157KP0NJLE7U";

  private final PrivateKey pvt;

  static PrivateKey loadDemoKey()
    throws Exception
  {
    /* Convert the embedded server public key into a PrivateKey object. */
    KeyFactory kf = KeyFactory.getInstance("DiffieHellman");
    byte[] decoded = new BigInteger(Server.demo, 32).toByteArray();
    return kf.generatePrivate(new PKCS8EncodedKeySpec(decoded));
  }

  Server(PrivateKey pvt)
  {
    this.pvt = pvt;
  }

  public String decrypt(byte[] packet)
    throws Exception
  {
    /* Deconstruct packet. */
    int len = 0;
    for (int idx = 0; idx < 4; ++idx)
      len |= ((packet[idx] & 0xFF) << 8 * idx);
    byte[] pub = new byte[len];
    System.arraycopy(packet, 4, pub, 0, len);
    KeyFactory kf = KeyFactory.getInstance("DiffieHellman");
    PublicKey client = kf.generatePublic(new X509EncodedKeySpec(pub));
    IvParameterSpec iv = new IvParameterSpec(packet, len + 4, 16);
    /* Perform key agreement to determine secret key. */
    KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman");
    ka.init(pvt);
    ka.doPhase(client, true);
    byte[] raw = ka.generateSecret();
    SecretKeySpec secret;
    try {
      secret = new SecretKeySpec(raw, 0, 16, "AES");
    }
    finally {
      Arrays.fill(raw, (byte) 0);
    }
    /* Setup cipher for decryption with secret key. */
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, iv);
    byte[] plaintext = cipher.doFinal(packet, len + 20, packet.length - (len + 20));
    try {
      return new String(plaintext, "UTF-8");
    }
    finally {
      Arrays.fill(plaintext, (byte) 0);
    }
  }

}

这篇关于Java中的电话到服务器通信加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆