簡體   English   中英

打印出來! printf 內含 swift 代碼

[英]Printing out ! with printf inside swift code

我正在嘗試用 openssl 加密一個字符串。要加密的字符串是由字母、數字和符號組成的隨機生成的字符串。 運行以下命令以嘗試加密字符串:

printf "randomString" | openssl enc -base64 -e -aes-256-cbc -salt -pass pass: "passwordSalt"

只要字符串中沒有生成任何 printf 不喜歡的字符,這就可以正常工作。 我看過其他關於通過將兩個百分比放在一起來處理%的帖子%%

但是,如果有! 在字符串中。 其他來源說單引號字符串而不是雙引號,因為雙引號導致 bash 插入字符串。 如果我只是在命令行中運行它,這將不是問題。 printf和 openssl 命令在 swift 中作為Process()運行,不幸的是在 swift 中沒有單引號這樣的東西。我什至嘗試在字符串生成后用單引號括起來,但這會導致單引號在加密期間成為字符串的一部分。 printf 是否提供了允許使用 a 的任何方式或選項? 當雙引號不是一個選項時在字符串中? echo也以類似的方式工作,其中單引號有效,但雙引號插入某些字符,但我可以使用echoprintf

停止使用printf並將輸入字符串直接寫入openssl的標准輸入。 那么你就不用擔心引用奇怪的字符了。

import Foundation

func encrypt(_ plainText: String) async throws -> String? {
    let pipeToChild = Pipe()
    let fileHandleToChild = pipeToChild.fileHandleForWriting
    let pipeFromChild = Pipe()
    let fileHandleFromChild = pipeFromChild.fileHandleForReading
    let child = Process()
    child.executableURL = URL(fileURLWithPath: "/usr/bin/openssl")
    child.arguments = [
        "enc",
        "-base64",
        "-e",
        "-aes-256-cbc",
        "-salt",
        "-pass", "pass:passwordSalt"
    ]
    child.standardInput = pipeToChild
    child.standardOutput = pipeFromChild
    try child.run()

    async let writeResult: () = Task {
        try fileHandleToChild.write(contentsOf: plainText.data(using: .utf8)!)
        try fileHandleToChild.close()
    }.value

    async let readResult = Task {
        try fileHandleFromChild.readToEnd()
    }.value

    let _ = try await writeResult
    let data = try await readResult

    return data.flatMap { String(data: $0, encoding: .utf8) }
}

@main
struct MyMain {
    static func main() async {
        do {
            let answer = try await encrypt(#"string with \/\/eird ${embedded} "c"harac't'ers"#)
            print(answer ?? "(failed to encrypt)")
        }

        catch {
            print("error: \(error)")
        }
    }
}

更新

這是一個不使用async的版本。 如果openssl在讀取其所有輸入之前嘗試寫入大量 output,理論上它可能會死鎖。 如果明文不超過 4k,這可能不會有問題。

import Foundation

func encrypt(_ plainText: String) throws -> String? {
    let pipeToChild = Pipe()
    let fileHandleToChild = pipeToChild.fileHandleForWriting
    let pipeFromChild = Pipe()
    let fileHandleFromChild = pipeFromChild.fileHandleForReading
    let child = Process()
    child.executableURL = URL(fileURLWithPath: "/usr/bin/openssl")
    child.arguments = [
        "enc",
        "-base64",
        "-e",
        "-aes-256-cbc",
        "-salt",
        "-pass", "pass:passwordSalt"
    ]
    child.standardInput = pipeToChild
    child.standardOutput = pipeFromChild
    try child.run()

    try fileHandleToChild.write(contentsOf: plainText.data(using: .utf8)!)
    try fileHandleToChild.close()

    let data = try fileHandleFromChild.readToEnd()
    return data.flatMap { String(data: $0, encoding: .utf8) }
}

@main
struct MyMain {
    static func main() {
        do {
            let answer = try encrypt(#"string with \/\/eird ${embedded} "c"harac't'ers"#)
            print(answer ?? "(failed to encrypt)")
        }

        catch {
            print("error: \(error)")
        }
    }
}

做這個

printf '%s' 'randomString' | openssl enc -base64 -e -aes-256-cbc -salt -pass pass: "passwordSalt"

避免通過printf解釋特殊格式字符

編輯

使用單引號

printf '%s' '!@#$%%^&*()_+=-0987654321\][{}|;:/.?>,<'
!@#$%%^&*()_+=-0987654321\][{}|;:/.?>,<

在@rob mayoff 的幫助下,我能夠完全避免將 printf/echo 管道傳輸到 openssl。 盡管我確實認為這仍然是一個可能最終需要回答的話題。 我能夠將 pipe 字符串發送到 swift 中的 openssl 進程:

mutating func encryptString(_ plainText: String) throws -> String? {
   let pipeToChild = Pipe()
   let fileHandleToChild = pipeToChild.fileHandleForWriting
   let pipeFromChild = Pipe()
   let fileHandleFromChild = pipeFromChild.fileHandleForReading
   let child = Process()
   child.executableURL = URL(fileURLWithPath: "/usr/bin/openssl")
   child.arguments = [
            "enc",
            "-base64",
            "-e",
            "-aes-256-cbc",
            "-salt",
            "-pass", "pass:\(self.passwordSalt)"
   ]
   child.standardInput = pipeToChild
   child.standardOutput = pipeFromChild
   try child.run()
   try fileHandleToChild.write(contentsOf: plainText.data(using: .utf8)!)
   try fileHandleToChild.close()
   var output = try fileHandleFromChild.readToEnd()
   var outputString = String(decoding: output!, as: UTF8.self)
   print("output: \(output!)")
   child.waitUntilExit()
   print("encrypted String: \(outputString)")
   self.encryptedPassword = outputString
   return "Success"
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM