douqiu0351 2012-01-31 22:54
浏览 62

将基于PHP mcrypt的安全性转换为Java基础(已修改为cryptastic)

after struggling for a while, I figured that I should bring my question here as I do not really know exactly what I am doing. Basically, I am using a somewhat modified version of the cryptastic version found here.

I am currently base64 encoding everything, then converting to hexidecimal in order to keep the data the same between the two langauges. Right now, I have managed to get decryption from PHP to work, but keep coming across errors when I try to encrypt. I am using BouncyCastle... and for some reason in the decrypt when I do an init, instead of using false it will only work with true (which the docs say is for encryption...) Anyway, here is my class thus far if anyone has a chance to look at it that would be great.

Technically, decrypt is working only because I have a hack function to remove padding as the ZeroByteEncoding isn't working properly either.

So, I am able to decrypt from the PHP cryptastic, but not encrypt properly so that it can decrypt (it throws an error in my stringToHexidecimal then)

public class Cryptastic {
public final static String CHARSET = "US-ASCII";

public byte[] encrypt(String toEncrypt, byte[] keyBytes, boolean base64Encode)
{
    try
    {
        toEncrypt = serialize(toEncrypt);
        byte[] newEncrypt = toEncrypt.getBytes(CHARSET);
        BlockCipher blockCipher = new RijndaelEngine(256);
        SecureRandom secureRandom = new SecureRandom();
        byte[] iv = new byte[32];           
        secureRandom.nextBytes(iv);


        CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
        RijndaelEngine rijndael = new RijndaelEngine(256);
        SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
        cipher.init(true, cipherParameters);

        int size = cipher.getOutputSize(newEncrypt.length);
        byte[] encrypted = new byte[size];
        System.out.println(displayBytes(encrypted, false));
        int outputLength = cipher.processBytes(newEncrypt, 0, newEncrypt.length, encrypted, 0);
        cipher.doFinal(encrypted, outputLength);
        if(base64Encode)
        {
            encrypted = Base64.encode(encrypted);
        }

        byte[] temp = new byte[encrypted.length + 32];
        for(int i = 0; i < iv.length; i++)
        {
            temp[i] = iv[i];
        }
        for(int i = iv.length; i < temp.length; i++)
        {
            temp[i] = encrypted[i - iv.length];
        }

        encrypted = temp;
        byte[] mac  = generateKey(encrypted, keyBytes, 1000, 32);

        temp = new byte[encrypted.length + mac.length];
        for(int i = 0; i < encrypted.length; i++)
        {
            temp[i] = encrypted[i];
        }
        for(int i = encrypted.length; i < temp.length; i++)
        {
            temp[i] = mac[i - encrypted.length];
        }

        return encrypted;

        //System.out.println("Original IV: " + displayBytes(iv, false));
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}

public byte[] decrypt(String toDecrypt, byte[] keyBytes, boolean base64Encode)
{
    try
    {
        byte[] newDecrypt = hexToByte(toDecrypt);
        //toDecrypt = hexToString(toDecrypt);
        if(base64Encode)
        {
            newDecrypt = Base64.decode(newDecrypt);
            //toDecrypt = new String(Base64.decode(toDecrypt.getBytes(CHARSET)), CHARSET);
        }    
        byte[] iv = new byte[32];
        byte[] extractedMac = new byte[32];

        int offset = newDecrypt.length - 32;
        for(int i = 0; i < 32; i++)
        {
            iv[i] = newDecrypt[i];
            extractedMac[i] = newDecrypt[i + offset];
        }

        byte[] temp = new byte[offset - 32];
        for(int i = 0; i < temp.length; i++)
        {
            temp[i] = newDecrypt[i + 32];
        }

        newDecrypt = temp;

        byte[] combo = new byte[newDecrypt.length + iv.length];
        for(int i = 0; i < iv.length; i++)
        {
            combo[i] = iv[i]; 
        }

        for(int i = iv.length; i < combo.length; i++)
        {
            combo[i] = newDecrypt[i - iv.length];
        }

        byte[] mac = generateKey(new String(combo, CHARSET), new String(keyBytes, CHARSET), 1000, 32);
        boolean matches = new String(extractedMac).equals(new String(mac));

        if(!matches)
        {
            byte[] toReturn = new byte[0];
            return toReturn;
        }

        CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
        RijndaelEngine rijndael = new RijndaelEngine(256);
        SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
        cipher.init(true, cipherParameters);

        int size = cipher.getOutputSize(newDecrypt.length);
        byte[] decrypted = new byte[size];

        System.out.println(displayBytes(newDecrypt, false));
        System.out.println(displayBytes(decrypted, false));
        int outputLength = cipher.processBytes(newDecrypt, 0, newDecrypt.length, decrypted, 0);
        cipher.doFinal(decrypted, outputLength);
        System.out.println(displayBytes(decrypted, false));

        temp = new byte[newDecrypt.length];
        for(int i = 0; i < temp.length; i++)
        {
            temp[i] = decrypted[i];
        }
        decrypted = temp;

        decrypted = unserialize(new String(decrypted, CHARSET)).getBytes(CHARSET);
        return decrypted;
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}

public byte[] generateKey(String password, String salt, int blockIterations, int keyLength)
{
    try
    {
        SHA256Digest digest = new SHA256Digest();
        int hashLength = digest.getDigestSize();
        long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
        String derived_key = "";
        //System.out.println("Number of blocks: " + keyBlocks);
        for(long block = 1; block <= keyBlocks; block++)
        {
            byte[] initialHash = hash_hmac(salt + new String(pack(block)/*, CHARSET */), password);
            byte[] compareHash = initialHash;
            //System.out.println("Block: " + block);
            for(int i = 1; i < blockIterations; i++) 
                // XOR each iterate
                compareHash = hash_hmac(compareHash, password);
                for(int j = 0; j < initialHash.length; j++)
                {
                    initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
                }
            }
            derived_key += new String(initialHash/*, CHARSET */);
        }
        return derived_key.substring(0, keyLength).getBytes(CHARSET);
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

    return null;
}

public byte[] generateKey(byte[] password, byte[] salt, int blockIterations, int keyLength)
{
    try
    {
        SHA256Digest digest = new SHA256Digest();
        int hashLength = digest.getDigestSize();
        long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
        byte[] derived_key = null;
        //System.out.println("Number of blocks: " + keyBlocks);
        for(long block = 1; block <= keyBlocks; block++)
        {
            byte[] packed = pack(block);
            byte[] combined = new byte[salt.length + packed.length];
            for(int i = 0; i < salt.length; i++)
            {
                combined[i] = salt[i];
            }
            for(int i = salt.length; i < combined.length; i++)
            {
                combined[i] = packed[i - salt.length];
            }

            byte[] initialHash = hash_hmac(combined, password);
            byte[] compareHash = initialHash;
            //System.out.println("Block: " + block);
            for(int i = 1; i < blockIterations; i++) 
            {
                // XOR each iterate
                compareHash = hash_hmac(compareHash, password);
                for(int j = 0; j < initialHash.length; j++)
                {
                    initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
                }
            }
            if(derived_key == null)
            {
                derived_key = initialHash;
            }
            else
            {
                byte[] temp = new byte[derived_key.length + initialHash.length];
                for(int i = 0; i < derived_key.length; i++)
                {
                    temp[i] = derived_key[i];
                }
                for(int i = derived_key.length; i < temp.length; i++)
                {
                    temp[i] = initialHash[i - derived_key.length];
                }
                derived_key = temp;
            }
        }
        byte[] toReturn = new byte[keyLength];
        for(int i = 0; i < toReturn.length; i++)
        {
            toReturn[i] = derived_key[i];
        }
        return toReturn;
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

    return null;
}

public byte[] pack(long toPack)
{       
    String test = Long.toHexString(toPack);
    while(test.length() < 8)
    {
        test = "0" + test;
    }       
    byte[] toReturn = new byte[4];

    toReturn[0] = Byte.parseByte(test.substring(0, 2));
    toReturn[1] = Byte.parseByte(test.substring(2, 4));
    toReturn[2] = Byte.parseByte(test.substring(4, 6));
    toReturn[3] = Byte.parseByte(test.substring(6, 8));
    return toReturn;
}

public String hexToString(String hex)
{
    return new String(hexToByte(hex));
}

public byte[] hexToByte(String hex)
{
    if(hex.length() % 2 != 0)
    {
        hex = "0" + hex;
    }

    byte[] toReturn = new byte[hex.length() / 2];

    for(int i = 0; i < toReturn.length; i++)
    {
        toReturn[i] = Byte.parseByte(hex.substring(i * 2, (i + 1) * 2), 16);
    }
    //System.out.println(displayBytes(toReturn, false));
    return toReturn;
}

public byte[] hash_hmac(String data, String key)
{
    return hash_hmac("HmacSHA256", data, key);
}

public byte[] hash_hmac(String algorithm , String data , String key)
{
    try
    {
        SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
        Mac mac = Mac.getInstance(algorithm);
        mac.init(secret);
        byte[] digest = mac.doFinal(data.getBytes(/*CHARSET*/));
        return digest;
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}

public byte[] hash_hmac(byte[] data, String key)
{
    return hash_hmac("HmacSHA256", data, key);
}

public byte[] hash_hmac(byte[] data, byte[] key)
{
    return hash_hmac("HmacSHA256", data, key);
}

public byte[] hash_hmac(String algorithm , byte[] data , byte[] key)
{
    try
    {
        SecretKeySpec secret = new SecretKeySpec(key, algorithm);
        Mac mac = Mac.getInstance(algorithm);
        mac.init(secret);
        byte[] digest = mac.doFinal(data);
        return digest;
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}

public byte[] hash_hmac(String algorithm , byte[] data , String key)
{
    try
    {
        SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
        Mac mac = Mac.getInstance(algorithm);
        mac.init(secret);
        byte[] digest = mac.doFinal(data);
        return digest;
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}


public String displayBytes(byte[] bytes, boolean rawDisplay)
{
    String toReturn = "";
    if(rawDisplay)
    {
            toReturn = new String(bytes/*, CHARSET */);
    }
    else
    {
        for (byte b : bytes) 
        {
            toReturn += String.format("%02x", b);
        }
    }
    return toReturn;
}

public String toHex(String toConvert) {
    if(toConvert.getBytes().length == 0)
    {
        return "";
    }
    return String.format("%04x", new BigInteger(toConvert.getBytes(/*YOUR_CHARSET?*/)));
}

/*
 * This creates a string representation that should line up with PHPs serialize.
 */
public String serialize(String toSerialize)
{
    return "s:" + toSerialize.length() + ":\"" + toSerialize + "\";";
}

public String unserialize(String toUnserialize)
{
    System.out.println(toUnserialize);
    int endIndex = toUnserialize.indexOf("\";");
    while (endIndex < toUnserialize.length() && endIndex < toUnserialize.indexOf("\";", endIndex + 1))
    {
        endIndex = toUnserialize.indexOf("\";", endIndex + 1);
    }
    return toUnserialize.substring(toUnserialize.indexOf(":\"") + 2, endIndex);
}
  • 写回答

2条回答 默认 最新

  • dopzc64662 2012-01-31 23:56
    关注

    Without reading through all the code, if an encrypt works instead of a decrypt, then you may have "decrypted" the plain text to form the cipher text, as symmetric encryption/decryption is reversable. In other words, you could use plain = encrypt(decrypt(plain)) as well as plain = decrypt(encrypt(plain)).

    The only possible difference could be padding: decrypt should remove padding and encrypt should add it, so that would make a difference.

    评论

报告相同问题?

悬赏问题

  • ¥15 如何在node.js中或者java中给wav格式的音频编码成sil格式呢
  • ¥15 不小心不正规的开发公司导致不给我们y码,
  • ¥15 我的代码无法在vc++中运行呀,错误很多
  • ¥50 求一个win系统下运行的可自动抓取arm64架构deb安装包和其依赖包的软件。
  • ¥60 fail to initialize keyboard hotkeys through kernel.0000000000
  • ¥30 ppOCRLabel导出识别结果失败
  • ¥15 Centos7 / PETGEM
  • ¥15 csmar数据进行spss描述性统计分析
  • ¥15 各位请问平行检验趋势图这样要怎么调整?说标准差差异太大了
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题