0

我有一个由三个服务组成的应用程序:ClientServerTokenService。为了访问服务器上的数据,客户端必须从TokenService获取SecurityToken对象。各方之间的通信使用共享密钥加密(客户端令牌服务共享一个密钥'A',令牌服务服务器共享一个不同的密钥'B')。当客户端向TokenService发送请求时,通信使用“A”加密。当TokenService返回时SecurityToken对象,该对象使用 B 和 A 加密,如下所示:((SecurityToken)B)A). 这个双重加密的对象首先返回给客户端客户端用 A 解密它,将它放入另一个对象中,附加一些附加信息(带有请求的字符串)并将其发送到服务器,在那里SecurityToken用 B 解密。

一切正常,直到我在服务器端解密SecurityToken对象。我得到例外:

 javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:749)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:675)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at mds.hm5.sharedclasses.Decryptor.decryptData(Decryptor.java:40)
at mds.hm5.tokenservice.Main2.main(Main2.java:28)

我能够像这样重新创建这个错误(各方之间没有远程通信):

public static void main(String[] args) {

    SecurityToken s = new SecurityToken(false, "2");

    try {
        byte[] bytes = Encryptor.getBytesFromObject(s);
        bytes = Encryptor.encryptData(bytes, "secretkey1");
        bytes = Encryptor.encryptData(bytes, "secretkey2");
        bytes = Base64.encodeBase64(bytes);

        System.out.println(bytes);

        bytes = Base64.decodeBase64(bytes);
        bytes = Decryptor.decryptData(bytes, "secretkey2");
        bytes = Decryptor.decryptData(bytes, "secretkey1");
        SecurityToken s2 = (SecurityToken) Decryptor.getObjectFromBytes(bytes);

        System.out.println(s2.getRole());

    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

我不知道我在这里做错了什么。就这样创建两层加密是不可能的吗?我错过了什么吗?

附加信息:

这是我的加密器类:

public class Encryptor {

public static byte[] encryptData(byte[] credentials, String key){

    Cipher c;
    SecretKeySpec k;
    byte[] byteCredentials = null;
    byte[] encryptedCredentials = null;
    byte[] byteSharedKey = null;

    try {

        byteCredentials = getBytesFromObject(credentials);
        byteSharedKey = getByteKey(key);

        c = Cipher.getInstance("AES");
        k = new SecretKeySpec(byteSharedKey, "AES");
        c.init(Cipher.ENCRYPT_MODE, k);
        encryptedCredentials = c.doFinal(byteCredentials);

    } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }

    return encryptedCredentials;

}

public static byte[] getBytesFromObject(Object credentials) throws IOException{

    //Hmmm.... now I'm thinking I should make generic type for both: Token and ITU_Credentials object, that would have this getBytes and getObject methods.
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutput out = null;
    byte[] newBytes = null;

    try {

      out = new ObjectOutputStream(bos);   
      out.writeObject(credentials);
      newBytes = bos.toByteArray();

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
      out.close();
      bos.close();
    }
    return newBytes;
}

private static byte[] getByteKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException{

    //Converting key to SHA-1 and trimming to mach maximum lenght of key

    byte[] bkey = key.getBytes("UTF-8");
    MessageDigest sha = MessageDigest.getInstance("SHA-1");
    bkey = sha.digest(bkey);
    bkey = Arrays.copyOf(bkey, 16);

    return bkey;
}

这是我的 Decryptor 类:

public class Decryptor {


public static byte[] decryptData(byte[] encryptedCredentials, String key){

    Cipher c;
    SecretKeySpec k;
    byte[] byteSharedKey = null;
    byte[] byteObject = null;


    try {

        byteSharedKey = getByteKey(key);

        c = Cipher.getInstance("AES");
        k = new SecretKeySpec(byteSharedKey, "AES");
        c.init(Cipher.DECRYPT_MODE, k);
        byteObject = c.doFinal(encryptedCredentials);



    } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }

    return byteObject;

}

public static Object getObjectFromBytes(byte[] credentials) throws IOException, ClassNotFoundException{

    ByteArrayInputStream bis = new ByteArrayInputStream(credentials);
    ObjectInput in = null;
    ITU_Credentials credentialsObj = null;

    try {

        in = new ObjectInputStream(bis);
        credentialsObj = (ITU_Credentials)in.readObject(); 

    } finally {
      bis.close();
      in.close();
    }
    return credentialsObj;
}


private static byte[] getByteKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException{

    //Converting key to SHA-1 and trimming to mach maximum lenght of key

    byte[] bkey = key.getBytes("UTF-8");
    MessageDigest sha = MessageDigest.getInstance("SHA-1");
    bkey = sha.digest(bkey);
    bkey = Arrays.copyOf(bkey, 16);

    return bkey;
}

public static void main(String[] args) {
    new Encryptor();
}

}

编辑:

按照建议,我将所有替换e.printStackTrace();throw new RuntimeException(e);类中的所有Decriptor内容以正确抛出异常:

public class Decryptor {


public static byte[] decryptData(byte[] encryptedCredentials, String key){

    Cipher c;
    SecretKeySpec k;
    byte[] byteSharedKey = null;
    byte[] byteObject = null;


    try {

        byteSharedKey = getByteKey(key);

        c = Cipher.getInstance("AES");
        k = new SecretKeySpec(byteSharedKey, "AES");
        c.init(Cipher.DECRYPT_MODE, k);
        byteObject = c.doFinal(encryptedCredentials);



    } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
        throw new RuntimeException(e);
    } catch (InvalidKeyException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    } catch (IllegalBlockSizeException e) {
        throw new RuntimeException(e);
    } catch (BadPaddingException e) {
        throw new RuntimeException(e);
    }

    return byteObject;

}

public static Object getObjectFromBytes(byte[] credentials) throws IOException, ClassNotFoundException{

    ByteArrayInputStream bis = new ByteArrayInputStream(credentials);
    ObjectInput in = null;
    ITU_Credentials credentialsObj = null;

    try {

        in = new ObjectInputStream(bis);
        credentialsObj = (ITU_Credentials)in.readObject(); 

    } finally {
      bis.close();
      in.close();
    }
    return credentialsObj;
}


private static byte[] getByteKey(String key) throws UnsupportedEncodingException, NoSuchAlgorithmException{

    //Converting key to SHA-1 and trimming to mach maximum lenght of key

    byte[] bkey = key.getBytes("UTF-8");
    MessageDigest sha = MessageDigest.getInstance("SHA-1");
    bkey = sha.digest(bkey);
    bkey = Arrays.copyOf(bkey, 16);

    return bkey;
}

public static void main(String[] args) {
    new Encryptor();
}

}

现在异常如下所示:

Exception in thread "main" java.lang.RuntimeException: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at mds.hm5.sharedclasses.Decryptor.decryptData(Decryptor.java:51)
at mds.hm5.tokenservice.Main2.main(Main2.java:28)
Caused by: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:749)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:675)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at mds.hm5.sharedclasses.Decryptor.decryptData(Decryptor.java:40)
... 1 more
4

1 回答 1

1

我认为你的问题的根源是:

byte[] bytes = Encryptor.getBytesFromObject(s);
bytes = Encryptor.encryptData(bytes, "secretkey1");

去:

//etc.//
byte[] encryptedCredentials = null;
byte[] byteSharedKey = null;

try {
    byteCredentials = getBytesFromObject(credentials);
    //Whoops!  credentials is already a byte array.
//etc.//
catch (and eat) exception.....
return encryptedCredentials;

而且,由于您吃掉了异常并只返回 null,正如 home 在评论中所建议的那样,所以它会继续移动,直到它进入解密步骤,在那里它会引发您没有预料到的异常(当它无法解密时,一个 IllegalBlockSizeException ,它不是您在那里捕获的八种异常类型中的任何一种),并为您提供了一些有用的东西。

这就是我认为正在发生的事情。

于 2012-11-20T17:47:38.387 回答