简体   繁体   English

打印出来! printf 内含 swift 代码

[英]Printing out ! with printf inside swift code

I'm attempting to encrypt a string with openssl. The string that is to be encrypted is a randomly generated string consisting of letters, numbers, and symbols.我正在尝试用 openssl 加密一个字符串。要加密的字符串是由字母、数字和符号组成的随机生成的字符串。 The following command is run to attempt to encrypt the string:运行以下命令以尝试加密字符串:

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

This works fine as long as there weren't any characters generated in the string that printf doesn't like.只要字符串中没有生成任何 printf 不喜欢的字符,这就可以正常工作。 I've seen other posts about handling a % by putting two percentage's together %% .我看过其他关于通过将两个百分比放在一起来处理%的帖子%%

However, issues arise if there is a !但是,如果有! in the string.在字符串中。 Other sources say to single quote the string instead of double quoting, as double quoting causes bash to interpolate the string.其他来源说单引号字符串而不是双引号,因为双引号导致 bash 插入字符串。 This wouldn't be an issue if I were just running this in the command line.如果我只是在命令行中运行它,这将不是问题。 The printf and openssl commands are being run in swift as a Process() and unfortunately there is no such thing as single quotes in swift. I've even tried to enclose the string in single quotes after it's generated but that causes the single quotes to be part of the string during encryption. printf和 openssl 命令在 swift 中作为Process()运行,不幸的是在 swift 中没有单引号这样的东西。我什至尝试在字符串生成后用单引号括起来,但这会导致单引号在加密期间成为字符串的一部分。 Is there any way or any option provided with printf that allows the use of a? printf 是否提供了允许使用 a 的任何方式或选项? in a string when double quotes aren't an option?当双引号不是一个选项时在字符串中? echo also works in a similar fashion, where single quoting works but double quotes interpolates certain characters, but I will be fine with using echo or printf . echo也以类似的方式工作,其中单引号有效,但双引号插入某些字符,但我可以使用echoprintf

Stop mucking about with printf and just write the input string directly to the standard input of openssl .停止使用printf并将输入字符串直接写入openssl的标准输入。 Then you don't need to worry about quoting weird characters.那么你就不用担心引用奇怪的字符了。

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)")
        }
    }
}

UPDATE更新

Here is a version that doesn't use async .这是一个不使用async的版本。 It could in theory deadlock if openssl tries to write substantial output before reading all of its input.如果openssl在读取其所有输入之前尝试写入大量 output,理论上它可能会死锁。 It probably won't be a problem if the plaintext is no more than 4k.如果明文不超过 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)")
        }
    }
}

Do this做这个

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

to avoid interpreting special format chars by printf避免通过printf解释特殊格式字符

edit编辑

use single quotes使用单引号

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

With assistance from @rob mayoff I was able to avoid the piping of printf/echo to openssl altogether.在@rob mayoff 的帮助下,我能够完全避免将 printf/echo 管道传输到 openssl。 Although I do think it's still a topic that probably needs to be answered ultimately.尽管我确实认为这仍然是一个可能最终需要回答的话题。 I was able to pipe a string to the openssl process in swift:我能够将 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