加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 问题将Base64字符串转换为十六进制字符串

发布时间:2020-12-15 02:12:12 所属栏目:Java 来源:网络整理
导读:TLDR: 我遗漏的边缘情况是什么,或者我的算法中将Base64字符串转换为十六进制字符串是否有错误? 我最近决定尝试Matasano Crypto Challenges,但无论出于何种原因,我决定尝试编写第一个挑战,而不使用库来转换Hex和Base64字符串. 我已经设法让Hex到Base64转换
TLDR:
我遗漏的边缘情况是什么,或者我的算法中将Base64字符串转换为十六进制字符串是否有错误?

我最近决定尝试Matasano Crypto Challenges,但无论出于何种原因,我决定尝试编写第一个挑战,而不使用库来转换Hex和Base64字符串.

我已经设法让Hex到Base64转换工作,但是从输出中可以看出,当我尝试将Base64转换回Hex时会有轻微的异常(例如,将Base64的最后四个值与Hex输出进行比较) ).

Hex To Base64:
Should Print: SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t
Actually Prints: SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t

Base64 to Hex:
Should Print: 49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d
Actually Prints: 49276d206b696c6c696e6720796e717220627261696e206c696b65206120706e69732e6e6f3573206c717328726f2e6d

我使用https://conv.darkbyte.ru/来检查我的一些值,并假设该站点上的代码是正确的,似乎我的问题是从Base64获取Base10表示,而不是从Base10到Hex:

Decimal Equivalent

My Output:
73,39,109,32,107,105,108,110,103,121,110,113,114,98,97,101,112,115,46,111,53,108,40,109

Site’s Output:
73,111,117,109,104,109

似乎所有带错误的值都聚集在40-60和100-120之间,但我不确定从那里到底要去哪里.我猜是有一些边缘情况我会注意处理,但我不确定那会是什么.

相关代码:

private static final Character[] base64Order = new Character[] { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',};

    private static final Character[] hexOrder = new Character[] { '0','f' };

public static String base64ToHex(String base64) throws Exception {
    if (base64.length() % 4 != 0 || base64.contains("[^a-zA-Z0-9+/]"))
        throw new Exception("InputNotBase64");
    else {
        int charValue = 0;
        int index = 0;
        String hex = "";
        BitSet bits = new BitSet();
        for (int i = 0; i < base64.length(); i++) {
            charValue = base64.charAt(i);
            // get actual value from ASCII table
            if (charValue > 64 && charValue < 91)
                charValue -= 65;
            if (charValue > 96 && charValue < 123)
                charValue -= 71;
            /// loop that adds to the BitSet reads right-to-left,so reverse
            // the bits and then shift
            charValue = Integer.reverse(charValue << 24) & 0xff;
            charValue >>= 2;
            // append binary values to the BitSet
            while (charValue != 0L) {
                if (charValue % 2 != 0) {
                    bits.set(index);
                }
                index++;
                charValue >>= 1;
            }
            // account for trailing 0s
            while (index % 6 != 0) {
                index++;
            }
        }
        // read 8-bit integer value for hex-value lookup
        String temp;
        int remainder;
        for (int i = 0; i < index; i++) {
            charValue = (charValue | (bits.get(i) ? 1 : 0));
            if ((i + 1) % 8 == 0) {
                temp = "";
                while (charValue != 0L) {
                    remainder = charValue % 16;
                    temp = hexOrder[remainder] + temp;
                    charValue /= 16;
                }
                hex += temp;
            }
            charValue <<= 1;
        }
        return hex;
    }
}

解决方法

您忘记在代码中处理以下字符:’0′,’1′,’2′,’3′,’4′,’5′,’6′,’7′,’8′,’9′,’ ‘,’/’
如果您替换以下代码

if (charValue > 64 && charValue < 91)
    charValue -= 65;
if (charValue > 96 && charValue < 123)
    charValue -= 71;

通过

charValue = getPositionInBase64(charValue);

哪里

public static int getPositionInBase64(int n)
{
    for (int p = 0; p < base64Order.length; p++)
    {
        if (n == base64Order[p])
        {
            return p;
        }
    }
    return -1;
}

一切正常

此外,当您使用字符而不是幻数时,代码更易读

if (charValue >= 'A' && charValue <= 'Z')
    charValue -= 'A';
...

在这种情况下,发现问题更容易

因为你问我正在提出可能的改进来加速计算.

准备下表并初始化一次

// index = character,value = index of character from base64Order
private static final int[] base64ToInt = new int[128];

public static void initBase64ToIntTable()
{
    for (int i = 0; i < base64Order.length; i++)
    {
        base64ToInt[base64Order[i]] = i;
    }
}

现在您可以通过简单的操作替换您的if / else链

charValue = base64ToInt[base64.charAt(i)];

使用这个我写的方法比你的方法快几倍

private static String intToHex(int n)
{
    return String.valueOf(new char[] { hexOrder[n/16],hexOrder[n%16] });
}

public static String base64ToHexVer2(String base64) throws Exception
{
    StringBuilder hex = new StringBuilder(base64.length()*3/4); //capacity could be 3/4 of base64 string length
    if (base64.length() % 4 != 0 || base64.contains("[^a-zA-Z0-9+/]"))
    {
        throw new Exception("InputNotBase64");
    }
    else
    {
        for (int i = 0; i < base64.length(); i += 4)
        {
            int n0 = base64ToInt[base64.charAt(i)];
            int n1 = base64ToInt[base64.charAt(i+1)];
            int n2 = base64ToInt[base64.charAt(i+2)];
            int n3 = base64ToInt[base64.charAt(i+3)];
            // in descriptions I treat all 64 base chars as 6 bit
            // all 6 bites from 0 and 1st 2 from 1st (00000011 ........ ........)
            hex.append(intToHex(n0*4 + n1/16));
            // last 4 bites from 1st and first 4 from 2nd (........ 11112222 ........)
            hex.append(intToHex((n1%16)*16 + n2/4));
            // last 2 bites from 2nd and all from 3rd (........ ........ 22333333)
            hex.append(intToHex((n2%4)*64 + n3));
        }
    }
    return hex.toString();
}

我认为这段代码更快,主要是因为简单的转换为十六进制.如果您想要并且需要它,您可以测试它.

要测试速度,您可以使用以下构造

String b64 = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t";
    try
    {
        Base64ToHex.initBase64ToIntTable();
        System.out.println(Base64ToHex.base64ToHex(b64));
        System.out.println(Base64ToHex.base64ToHexVer2(b64));

        int howManyIterations = 100000;
        Date start,stop;
        long period;

        start = new Date();
        for (int i = 0; i < howManyIterations; i++)
        {
            Base64ToHex.base64ToHexVer2(b64);
        }
        stop = new Date();
        period = stop.getTime() - start.getTime();
        System.out.println("Ver2 taken " + period + " ms");

        start = new Date();
        for (int i = 0; i < howManyIterations; i++)
        {
            Base64ToHex.base64ToHex(b64);
        }
        stop = new Date();
        period = stop.getTime() - start.getTime();
        System.out.println("Ver1 taken " + period + " ms");

    }
    catch (Exception ex)
    {
    }

示例结果是

49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d
49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d
Ver2 taken 300 ms
Ver1 taken 2080 ms

但它只是近似值.当您首先检查Ver1而将Ver2检查为第二个时,结果可能会略有不同.另外,对于不同的javas(第6,7,8)以及用于启动java的不同设置,结果可能不同

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读