【问题标题】:Convert base64-encoded string to normal string in swift 3在swift 3中将base64编码的字符串转换为普通字符串
【发布时间】:2017-01-06 12:01:07
【问题描述】:

我想在 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 中提到)和 base64 中的 iv(上面给出),他指示我在使用之前解码这个 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???@???

【问题讨论】:

标签: character-encoding swift3 base64


【解决方案1】:

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

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

生成的ivArray&lt;UInt8&gt;(也称为[UInt8])。您可以将其与 AES 函数一起使用。

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


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

底线,我建议您完全放弃“如何获取此 base-64 字符串中捕获的数据的字符串表示形式”查询行。如果它是加密密钥(或某些令牌或其他),请不要费心尝试将其表示为字符串。 (这是 base-64 的存在理由,用于创建非字符串数据的可传输字符串表示形式。)

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

如果没有更多关于您从哪里获得这些数据及其用途的背景信息,我们无法回答这个问题。

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


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

75f61c48 6a6f06ac b3be4017 91d6c70c

但该有效负载不是有效的 UTF8 字符串。第三个字节1c 与UTF8 字符串不一致。如果您查看definition of UTF8,它表示如果一个字节在f6fb 的范围内,即第二个字节,则该字符由该字节和后面的两个字节组成,这两个字节都应该在217ea0ff 的范围内,1c 不在。

所以,这根本不是一个有效的 UTF8 字符串。很明显,您使用的那些网站并没有优雅地检测/处理无效的 UTF8 字符串。

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

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

【讨论】:

  • 显然这些网站以 ISO 拉丁编码解释数据,我想知道 OP 从讨论中学到了什么并回答了他之前的问题:(
  • @MartinR - 也许吧。或者他们根本没有进行错误检测(因为如果您明确选择 UTF8,第一个站点仍然会显示一个字符串)。坦率地说,当我注意到他们没有检测到 UTF8 字符串表示错误时,我对这些网站失去了信心,这就是为什么我回到 UTF8 的定义来确认。
  • 当然,你完全正确。 – 如果您使用.isoLatin1 转换给定数据,那么结果是uöHjo¬³¾@‘ÖÇ,这是OP 所期望的。但是我们在他之前的问题中与 OP 讨论了所有这些问题,我很想将其作为重复项关闭...
  • @MartinR - 很好。但我仍然不会假设那是原始字符串,并且他们明确获得了 latin-1 表示,然后将其转换为 base-64 字符串表示。更有可能的是,原始有效负载根本不是字符串,并且 OP 在尝试将其表示为字符串时一直被误导。但我们只是在猜测,直到 OP 告诉我们那个 base-64 编码的有效载荷的来源。
  • 正是我的意思(也许我表达得不好)。在上一个问题中,它是一个 AES 密钥,我在回答中建议将其作为字节数组传递给 AES init 函数,而不将其转换为字符串。当然不知道这里是不是同样的问题。
猜你喜欢
  • 2017-03-07
  • 1970-01-01
  • 2019-02-16
  • 1970-01-01
  • 1970-01-01
  • 2018-08-05
  • 2014-04-08
  • 2016-01-21
  • 2015-06-04
相关资源
最近更新 更多