-
-
Notifications
You must be signed in to change notification settings - Fork 514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Windows PowerShell 5.1 output file redirection corrupts files #290
Comments
This is actually a Windows problem. Windows uses UTF-16 instead of UTF-8 as its base format, so when encoding ASCII strings as bytes you end up with extra bytes. If you look carefully at the store message, you can see it is The interim solution here is to use armored output (the However, there is a real bug here: |
That narrows down the location of the bug, thanks! |
The header line in question is written here: Line 140 in 4ea591b
Are you using a binary build of |
I simply downloaded the "age-v1.0.0-rc.3-windows-amd64.zip" file from pre-built binaries page on your Github repo. Nothing else I did. |
Facing the same issue with v1.0.0-rc.3 |
This came up before, and as far as I know, this is a fundamental issue of PowerShell pipes and file redirection, and the way to fix it is to use |
According to the
That seems like the opposite of what @FiloSottile was seeing? If so, it suggests this is a bug in PowerShell that might have been fixed, but for which we need to handle earlier versions (ugh). |
IIUC, the behavior changed with PowerShell Core 6.0. Apparently, PowerShell Core is NOT the Windows PowerShell that comes installed with Windows 10, which is still version 5.1. It sounds like PowerShell 7 is meant to eventually replace WIndows PowerShell but it hasn't yet.
https://docs.microsoft.com/en-us/powershell/scripting/whats-new/what-s-new-in-powershell-core-60?view=powershell-7.1&viewFallbackFrom=powershell-6#default-encoding-is-utf-8-without-a-bom-except-for-new-modulemanifest
https://devblogs.microsoft.com/powershell/powershell-7-road-map/
|
Ah, looks like in PowerShell 6+ the issue is not UTF-16 anymore, but the CRLF line endings. Again, we need to look for a way to say "this is binary, leave it alone". With PowerShell 6+, it should work with the |
In Powershell 6+, if we use -a armor flag during encryption, then after decryption the data becomes corrupted. Unable to retrieve the original data. |
@namitgpta that's unexpected, can you paste the command sequence and the corruption? |
This sums it up well: binref/refinery#5 I also wrote a snippet that writes the uint64 binary representation of the numbers 0 to 9 to a file and to stdout to compare the difference: https://play.golang.org/p/hCcSRcxGQ67 When writing to stdout, the newlines are converted to crlf (0d 0a). Writing to a file does exactly what you'd expect. It leaves the header intact, and it doesn't end with a trailing newline. That does mean that this is not easy to fix. |
The short version (having recently battled against PowerShell and Windows terminal subsystem) is that its best if the program (age) can write the file directly. It (really does) help to understand that whereas Unix systems treat content going through a pipe as bytestreams (or at least as character streams of usually 8-bit bytes with no regard to encoding), Windows (in its own also very long established lineage) treats them as 'text' streams, which for PowerShell and its modern terminal-subsystem means UTF-16 LittleEndian text streams with all the painful cross-platforming phun that can imply. (Arguably though, that's not correct since what flows across a '|' in PowerShell is really an object, but ...) So any documentation (for Windows at least) would be provide by using the Windows 10 (I'm on the latest; 20H1) with PowerShell will not provide a happy path when using redirections; the easiest way of using redirections is to redirect a textual output; then open it in an editor to change the encoding. That's about as close to a happy-path as you're likely to get at least until you can do Presumably should shouldn't be a problem if using WSL-2 or similar, but is sure is frustrating when trying to do DevOps kind of things in Windows (where I feel this kind of pain the most). |
https://github.com/tmclnk/RepoCrypto/blob/master/FileCryptography.psm1 As a work around would it be possible to support the encryption of a string of any size and return an encrypted string? The caller then would be responsible for dumping the encrypted string where ever they choose. |
This is a long-running issue affecting all versions of PowerShell (PowerShell/PowerShell#1908). Here are the results of running a small test program (https://go.dev/play/p/jlY_sKptwpP) on Windows 10. cmd.exe
Windows Powershell 5.1.19041.1320
Ubuntu 20.04 LTS bash
PowerShell 7.1.3
It doesn't look like there is any solution, besides using I would very much like to find a way to detect when age is running under PS (but not cmd.exe or WSL), and print a warning if neither |
I don't know about detecting PS or |
I would still like to find a way to offer a warning while doing the encryption, rather than at decryption time, but better than nothing. Updates #290
Comparing the environment I get in cmd versus powershell, there doesn't appear to be any reasonable difference (eg. PSModulePath is set for me in both), so looking at the environment doesn't appear useful. |
I took a brief look at this. If you want to print a warning when stdout is a pipe on windows, you could try something like: h, _ := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE)
fileType, _ := windows.GetFileType(h)
if fileType == windows.FILE_TYPE_PIPE {
fmt.Fprintf(os.Stderr, "age: some warning about pipes on windows. consider -o or -a\n")
} In some basic testing with PowerShell 5.1.19041.1320:
Is that too broad of a net to cast, or is it reasonable to have some properly phrased hint emitted on Windows if stdout is a pipe? Small test program: https://go.dev/play/p/YSUOeIe8VnP |
@thepudds, hi! That looks very promising. Is it FILE_TYPE_PIPE for |
Hi @FiloSottile, late reply, but FWIW, I did poke at it some more shortly after posting here, but neglected to circle back to report results. In short, by sniffing various aspects, I was able to distinguish between PowerShell vs. a normal command prompt, but was not able to simultaneously distinguish vs. a Cygwin terminal, which seemed to be a fatal-ish flaw (I think -- it's now been a while since I looked at it, so I might be misremembering the exact details). The (hopefully?) better news is there is new feature of PowerShell that greatly reduces the mangling that PowerShell does of pipes and redirects for native commands (such as Go binaries): I have some hope that this helps here, but I have not confirmed with age. I did just seem to briefly confirm with |
Environment
What were you trying to do
I was trying to encrypt a g1.txt file containing text passwords with help of a passphrase. It got successfully encrypted with filename g1.txt.age. But when I tried to decrypt it, it is showing this error (see screenshot).
What happened
Actually, the g1.txt file, which I am trying to encrypt, is already an encrypted file of passwords.
What I did is:
First, I encrypted my original txt file of passwords with help of AES pbkdf2 python program, which generated an encrypted file g1.txt. Then for further security, I thought that I should implement Age Encryption on the encrypted file itself (for double security). But after encryption, during decryption, it shows this error in windows terminal:
So, I think the Age algorithm is unable to encrypt data which is already encrypted.
The text was updated successfully, but these errors were encountered: