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\][{}|;:/.?>,<