将base64编码的字符串转换为swift 3

时间:2017-01-06 12:01:07

标签: character-encoding swift3 base64

我想在Swift 3中转换以下base64编码的String

dfYcSGpvBqyzvkAXkdbHDA==

等同于String

uöHjo¬³¾@‘ÖÇ

以下网站的工作非常好:

http://www.motobit.com/util/base64-decoder-encoder.asp

http://www.utilities-online.info/base64/#.WG-FwrFh2Rs

PHP的函数base64_decode也是如此。此函数的documentation表示:

  

如果输入包含base64外部的字符,则返回FALSE   字母表。

但我无法在Swift 3中做同样的事情。以下代码也不能完成这项工作:

func convertBase64ToNormalString(base64String:String)->String!{
   let decodedData = Data(base64Encoded: base64String, options:    Data.Base64DecodingOptions())
   let bytes = decodedData?.bytes
   return String(bytes: bytes, encoding: NSUTF8StringEncoding)
}

以下是有关我需要将base64字符串转换为字符串的原因的上下文信息: 我的Php开发人员希望我发送所有使用AES算法加密的API参数值。为此,我使用的是this lib。 他给了我十六进制格式的AES密钥(我在我的last question中提到)和iv在base64(上面给出)中,他指示我在使用之前解码这个base64密钥,因为他在PHP代码中也做了同样的事情。这是他的加密和解密PHP代码:

function encryptParamAES($plaintext, $encryptionEnabled = true) {
    if (! $encryptionEnabled) {
        return $plaintext;
    }
    // --- ENCRYPTION ---

    // Constants =========================================================
    // the key should be random binary, use scrypt, bcrypt or PBKDF2 to
    // convert a string into a key
    // key is specified using hexadecimal
    $key = pack ( 'H*', "dcb04a9e103a5cd8b53763051cef09bc66abe029fdebae5e1d417e2ffc2a07a4" );
    // create a random IV to use with CBC encoding
    $iv_size = 16;
    $iv = base64_decode ( "dfYcSGpvBqyzvkAXkdbHDA==" );

    // End Of constants ===================================================

    // echo "IV: " . base64_encode ( $iv ) . "\n<br>";
    // echo "IV Size: " . $iv_size . "\n<br>";

    // show key size use either 16, 24 or 32 byte keys for AES-128, 192
    // and 256 respectively

    // $key_size = strlen ( $key );
    // echo "Key size: " . $key_size . "\n<br><br>";

    // creates a cipher text compatible with AES (Rijndael block size = 128)
    // to keep the text confidential
    // only suitable for encoded input that never ends with value 00h
    // (because of default zero padding)
    $ciphertext = mcrypt_encrypt ( MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv );

    // prepend the IV for it to be available for decryption
    $ciphertext = $iv . $ciphertext;

    // encode the resulting cipher text so it can be represented by a string
    $ciphertext_base64 = base64_encode ( $ciphertext );

    return $ciphertext_base64;
}


function decryptParamAES($ciphertext_base64, $encryptionEnabled = true) {
    if (! $encryptionEnabled) {
        return $ciphertext_base64;
    }
    // --- DECRYPTION ---

    // Constants =========================================================
    // the key should be random binary, use scrypt, bcrypt or PBKDF2 to
    // convert a string into a key
    // key is specified using hexadecimal
    $key = pack ( 'H*', "dcb04a9e103a5cd8b53763051cef09bc66abe029fdebae5e1d417e2ffc2a07a4" );
    // create a random IV to use with CBC encoding
    $iv_size = 16;
    $iv = base64_decode ( "dfYcSGpvBqyzvkAXkdbHDA==" );

    // End Of constants ===================================================

    $ciphertext_dec = base64_decode ( $ciphertext_base64 );

    // retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
    $iv_dec = substr ( $ciphertext_dec, 0, $iv_size );

    // retrieves the cipher text (everything except the $iv_size in the front)
    $ciphertext_dec = substr ( $ciphertext_dec, $iv_size );

    // may remove 00h valued characters from end of plain text
    $plaintext_dec = mcrypt_decrypt ( MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec );
    return rtrim ( $plaintext_dec );
}

我刚刚看到这个PHP代码,并想知道为什么他不使用$ iv作为mcrypt_decrypt函数的最后一个参数!会更新你的。但问题仍然存在,PHP函数base64_decode不会为上述base64字符串返回FALSE! 我通过终端命令自己测试了这个功能:php test.php。这里test.php包含以下代码:

<?php
$iv = base64_decode ( "dfYcSGpvBqyzvkAXkdbHDA==" );
echo $iv;
?>

输出结果为:u?Hjo???@???

2 个答案:

答案 0 :(得分:1)

查看修改后的问题,您尝试使用此base-64字符串,并将其用作AES算法中的iv。我可以理解为什么您想知道如何将Data转换为String,但您不应该这样做。是的,有一个AES的格式,期望iv为字符串。但还有另一个版本需要Array<UInt8>。所以,就像MartinR在his answer to your other question中说的那样,构建一个UInt8的数组,就像这样:

let iv = Array(Data(base64Encoded: "dfYcSGpvBqyzvkAXkdbHDA==")!)

结果ivArray<UInt8>(也称为[UInt8])。您可以将其与AES功能一起使用。

我最初关于将Data个对象转换为UTF8字符串的讨论如下。但关键信息是你不应该试图这样做。只需构建UInt8数组,并将其与库AES函数一起使用。

查看您的其他问题(Convert hex-encoded String to String in Swift 3),您在评论中透露您正在处理AES密钥。我怀疑我们在这里处理类似的问题(尽管那是32字节的数据,这里我们有16个字节)。

最重要的是,我建议你完全放弃这个“如何获得在这个base-64字符串中捕获的数据的字符串表示”查询行。如果它是加密密钥(或某些令牌或其他),请不要试图将其表示为字符串。 (这是base-64的 raison d'être,用于创建非字符串数据的可传输字符串表示。)

我建议你退后一步,描述你想要解决的更广泛的问题。停止尝试从这些二进制有效负载中创建字符串。在您的代码段中,您已成功从base-64字符串创建Data。我认为,真正的问题不是“我现在如何从中获取字符串?”而是“我该怎么做Data?”

如果没有关于您获取此数据的位置及其用途的更多背景信息,我们无法回答该问题。

顺便说一下,我对你问题的原始答案如下。

问题是base-64字符串转换为16字节的数据,其十六进制表示为

75f61c48 6a6f06ac b3be4017 91d6c70c

但是那个有效载荷是无效的UTF8字符串。第三个字节1c与UTF8字符串不一致。如果你查看definition of UTF8,它会说如果一个字节在f6 - fb范围内,第二个字节是,那个字符由以下两个字符组成字节,两者都应在21 - 7ea0 - ff范围内,1c不是。

因此,这根本不是有效的UTF8字符串。显然,您正在使用的那些网站没有正常检测/处理无效的UTF8字符串。

也许这个base-64字符串中的数据是使用不同的编码从字符串转换而来的。或者,它可能根本不是一个字符串。并非所有二进制有效负载都具有干净的字符串表示坦率地说,这就是为什么我们首先使用base-64表示,以提出一个不是字符串的数据blob的文本表示。

如果您提供有关此base-64字符串中包含的数据来源的更多信息,我们可能会为您提供进一步的建议。

答案 1 :(得分:0)

我为同样的情况找到了很好的解决方案。看https://github.com/kylef/JSONWebToken.swift/blob/master/Sources/Base64.swift

我只是用于检查JWT的库,但你可以使用执行base64decode的func。