Home > Net >  Printing out ! with printf inside swift code
Printing out ! with printf inside swift code

Time:01-27

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. 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. 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. 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. Is there any way or any option provided with printf that allows the use of 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.

CodePudding user response:

Stop mucking about with printf and just write the input string directly to the standard input of 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. It could in theory deadlock if openssl tries to write substantial output before reading all of its input. It probably won't be a problem if the plaintext is no more than 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)")
        }
    }
}

CodePudding user response:

Do this

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

to avoid interpreting special format chars by printf

edit

use single quotes

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