Is it possible to check a pgp encrypted file without decrypting it? - pgp

On Linux, I have access to PGP. However, I do not have PGP SDK service running on a particular box to which I have access to.
Normally, I use "pgp --verify --passphrase " to verify the .pgp files.
Is it possible to verify a file (I only need to check if the file is encrypted or not) using pgp but not where PGP SDK service is required?

RHEL already brings GnuPG, which is a fully compliant implementation of OpenPGP. Using gpg --list-only --list-packets you can dump the contents of an OpenPGP file (either sending the contents into STDIN or providing an additional option containing a file name).
An example output for my own key:
$ echo foo | gpg --recipient a4ff2279 --encrypt | gpg2 --list-only --list-packets
# off=0 ctb=85 tag=1 hlen=3 plen=524
:pubkey enc packet: version 3, algo 1, keyid CC73B287A4388025
data: [4096 bits]
# off=527 ctb=d2 tag=18 hlen=2 plen=63 new-ctb
:encrypted data packet:
length: 63
mdc_method: 2
If you want to test for encrypted information, look for the :pubkey enc packet line if you only want to match public-private-key cryptography, the :encrypted data packet will be available in both public-private-key cryptography and with symmetric encryption.
PGP probably provides similar interfaces, but I have few experience with it and currently no setup around to play with it. Anyway, if using PGP make sure you're not using one of the very old, outdated versions suffering from some flaws and limited compatibility with newer releases of the standard.

Related

Signing Git commits using SSH key fails [duplicate]

What are the differences between SSH and GPG asymmetric keys and why does git support signing with GPG rather than using the SSH agent?
Update Sept. 2022: 1Password supports generating and storing an SSH key for Git commit signature, recognized by GitHub.
Update 2021:
OpenSSH 8.2+ is available (packaged for instance in Git For Windows 2.33.1), and "it is now possible to sign arbitrary data with your SSH keys" (Andrew Ayer), including commits in Git.
Andrew points to git/git PR 1041 "ssh signing: Add commit & tag signing/verification via SSH keys using ssh-keygen", now with Git 2.34 (Nov. 2021)
gpg.format will have a new value "ssh"
set gpg.format = ssh and user.signingkey to a ssh public key string (like from an authorized_keys file) and commits/tags can be signed using the private key from your ssh-agent.
Andrew adds:
Always be wary of repurposing cryptographic keys for a different protocol. If not done carefully, there's a risk of cross-protocol attacks.
For example, if the structure of the messages signed by Git is similar to the structure of SSH protocol messages, an attacker might be able to forge Git artifacts by misappropriating the signature from an SSH transcript.
Fortunately, the structure of SSH protocol messages and the structure of messages signed by ssh-keygen are dissimilar enough that there is no risk of confusion.
That comes from:
Git 2.34 (Q4 2021): use ssh public crypto for object and push-cert signing.
See commit 1bfb57f, commit f265f2d, commit 3326a78, commit facca53, commit 4838f62, commit fd9e226, commit 29b3157, commit 64625c7, commit b5726a5 (10 Sep 2021) by Fabian Stelzer (FStelzer).
(Merged by Junio C Hamano -- gitster -- in commit 18c6653, 25 Oct 2021)
ssh signing: verify signatures using ssh-keygen
Signed-off-by: Fabian Stelzer
To verify a ssh signature we first call ssh-keygen -Y find-principal to look up the signing principal by their public key from the allowedSignersFile.
If the key is found then we do a verify.
Otherwise we only validate the signature but can not verify the signers identity.
Verification uses the gpg.ssh.allowedSignersFile (see ssh-keygen(1) "ALLOWED SIGNERS") which contains valid public keys and a principal (usually user#domain).
Depending on the environment this file can be managed by the individual developer or for example generated by the central repository server from known ssh keys with push access.
This file is usually stored outside the repository, but if the repository only allows signed commits/pushes, the user might choose to store it in the repository.
To revoke a key put the public key without the principal prefix into gpg.ssh.revocationKeyring or generate a KRL (see ssh-keygen(1) "KEY REVOCATION LISTS").
The same considerations about who to trust for verification as with the allowedSignersFile apply.
Using SSH CA Keys with these files is also possible.
Add "cert-authority" as key option between the principal and the key to mark it as a CA and all keys signed by it as valid for this CA.
See "CERTIFICATES" in ssh-keygen(1).
git config now includes in its man page:
gpg.ssh.allowedSignersFile
A file containing ssh public keys which you are willing to trust.
The file consists of one or more lines of principals followed by an ssh
public key.
e.g.: user1#example.com,user2#example.com ssh-rsa AAAAX1...
See ssh-keygen(1) "ALLOWED SIGNERS" for details.
The principal is only used to identify the key and is available when
verifying a signature.
SSH has no concept of trust levels like gpg does. To be able to differentiate
between valid signatures and trusted signatures the trust level of a signature
verification is set to fully when the public key is present in the allowedSignersFile.
Otherwise the trust level is undefined and git verify-commit/tag will fail.
This file can be set to a location outside of the repository and every developer
maintains their own trust store. A central repository server could generate this
file automatically from ssh keys with push access to verify the code against.
In a corporate setting this file is probably generated at a global location
from automation that already handles developer ssh keys.
A repository that only allows signed commits can store the file
in the repository itself using a path relative to the top-level of the working tree.
This way only committers with an already valid key can add or change keys in the keyring.
Using a SSH CA key with the cert-authority option
(see ssh-keygen(1) "CERTIFICATES") is also valid.
gpg.ssh.revocationFile
Either a SSH KRL or a list of revoked public keys (without the principal prefix).
See ssh-keygen(1) for details.
If a public key is found in this file then it will always be treated
as having trust level "never" and signatures will show as invalid.
With Git 2.35 (Q1 2022), extend the signing of objects with SSH keys and learn to pay attention to the key validity time range when verifying.
See commit 50992f9, commit 122842f, commit dd3aa41, commit 4bbf378, commit 6393c95, commit 30770aa, commit 0276943, commit cafd345, commit 5a2c1c0 (09 Dec 2021) by Fabian Stelzer (FStelzer).
(Merged by Junio C Hamano -- gitster -- in commit d2f0b72, 21 Dec 2021)
ssh signing: make verify-commit consider key lifetime
Signed-off-by: Fabian Stelzer
If valid-before/after dates are configured for this signatures key in the allowedSigners file then the verification should check if the key was valid at the time the commit was made.
This allows for graceful key rollover and revoking keys without invalidating all previous commits.
This feature needs openssh > 8.8.
Older ssh-keygen versions will simply ignore this flag and use the current time.
Strictly speaking this feature is available in 8.7, but since 8.7 has a bug that makes it unusable in another needed call we require 8.8.
Timestamp information is present on most invocations of check_signature.
However signer ident is not.
We will need the signer email / name to be able to implement "Trust on first use" functionality later.
Since the payload contains all necessary information we can parse it from there.
The caller only needs to provide us some info about the payload by setting payload_type in the signature_check struct.
Add payload_type field & enum and payload_timestamp to struct `signature_check
Populate the timestamp when not already set if we know about the payload type
Pass -Overify-time={payload_timestamp} in the users timezone to all ssh-keygen verification calls
Set the payload type when verifying commits
Add tests for expired, not yet valid and keys having a commit date outside of key validity as well as within
git config now includes in its man page:
Since OpensSSH 8.8 this file allows specifying a key lifetime using valid-after &
valid-before options.
Git will mark signatures as valid if the signing key was
valid at the time of the signatures creation.
This allows users to change a
signing key without invalidating all previously made signatures.
And, still with Git 2.35 (Q1 2022), the cryptographic signing using ssh keys can specify literal keys for keytypes whose name do not begin with the "ssh-" prefix by using the "key::" prefix mechanism
(e.g. "key::ecdsa-sha2-nistp256").
See commit 3b4b5a7, commit 350a251 (19 Nov 2021) by Fabian Stelzer (FStelzer).
(Merged by Junio C Hamano -- gitster -- in commit ee1dc49, 21 Dec 2021)
ssh signing: support non ssh-* keytypes
Signed-off-by: Fabian Stelzer
The user.signingKey config for ssh signing supports either a path to a file containing the key or for the sake of convenience a literal string with the ssh public key.
To differentiate between those two cases we check if the first few characters contain "ssh-" which is unlikely to be the start of a path.
ssh supports other key types which are not prefixed with "ssh-" and will currently be treated as a file path and therefore fail to load.
To remedy this we move the prefix check into its own function and introduce the prefix key:: for literal ssh keys.
This way we don't need to add new key types when they become available.
The existing ssh- prefix is retained for compatibility with current user configs but removed from the official documentation to discourage its use.
git config now includes in its man page:
If gpg.format is set to ssh this can contain the path to either
your private ssh key or the public key when ssh-agent is used.
Alternatively it can contain a public key prefixed with key::
directly (e.g.: "key::ssh-rsa XXXXXX identifier").
The private key
needs to be available via ssh-agent.
If not set git will call
gpg.ssh.defaultKeyCommand (e.g.: "ssh-add -L") and try to use the
first key available.
For backward compatibility, a raw key which
begins with "ssh-", such as "ssh-rsa XXXXXX identifier", is treated
as "key::ssh-rsa XXXXXX identifier", but this form is deprecated;
use the key:: form instead.
"git merge $signed_tag"(man) started to drop the tag message from the default merge message it uses by accident, which has been corrected with Git 2.35 (Q1 2022).
See commit c39fc06 (10 Jan 2022) by Taylor Blau (ttaylorr).
(Merged by Junio C Hamano -- gitster -- in commit cde28af, 12 Jan 2022)
fmt-merge-msg: prevent use-after-free with signed tags
Reported-by: Linus Torvalds
Signed-off-by: Taylor Blau
When merging a signed tag, fmt_merge_msg_sigs() is responsible for populating the body of the merge message with the names of the signed tags, their signatures, and the validity of those signatures.
In 0276943 ("ssh signing: use sigc struct to pass payload", 2021-12-09, Git v2.35.0-rc0 -- merge listed in batch #4), check_signature() was taught to pass the object payload via the sigc struct instead of passing the payload buffer separately.
In effect, 0276943 causes buf, and sigc.payload to point at the same region in memory.
This causes a problem for fmt_tag_signature(), which wants to read from this location, since it is freed beforehand by signature_check_clear() (which frees it via sigc's payload member).
That makes the subsequent use in fmt_tag_signature() a use-after-free.
As a result, merge messages did not contain the body of any signed tags.
Luckily, they tend not to contain garbage, either, since the result of strstr()-ing the object buffer in fmt_tag_signature() is guarded:
const char *tag_body = strstr(buf, "\n\n");
if (tag_body) {
tag_body += 2;
strbuf_add(tagbuf, tag_body, buf + len - tag_body);
}
Resolve this by waiting to call signature_check_clear() until after its contents can be safely discarded.
Harden ourselves against any future regressions in this area by making sure we can find signed tag messages in the output of fmt-merge-msg, too.
Original answer (2017): The very first notion of signing anything in Git was referenced in commit ec4465a, Git v0.99, Apr. 2005 (pretty much from the very beginning)
/**
* A signature file has a very simple fixed format: three lines
* of "object <sha1>" + "type <typename>" + "tag <tagname>",
* followed by some free-form signature that git itself doesn't
* care about, but that can be verified with gpg or similar.
**/
So your question has legs.
The very first signed commit used gpg, but could have used anything else (commit 65f0d0e):
#!/bin/sh
object=${2:-$(cat .git/HEAD)}
type=$(cat-file -t $object) || exit 1
( echo -e "object $object\ntype $type\ntag $1\n"; cat ) > .tmp-tag
rm -f .tmp-tag.asc
gpg -bsa .tmp-tag && cat .tmp-tag.asc >> .tmp-tag
git-mktag < .tmp-tag
#rm .tmp-tag .tmp-tag.sig
Technically, you can use gpg in place of ssh. I haven't seen often the reverse though.
But you can use an ssh key-pair be used with PGP/GPG.
That means the first validation script might still work (commit f336e71)... except it expected a PGP comment:
#!/bin/sh
GIT_DIR=${GIT_DIR:-.git}
tag=$1
[ -f "$GIT_DIR/refs/tags/$tag" ] && tag=$(cat "$GIT_DIR/refs/tags/$tag")
git-cat-file tag $tag > .tmp-vtag || exit 1
cat .tmp-vtag | sed '/-----BEGIN PGP/Q' | gpg --verify .tmp-vtag -
rm -f .tmp-vtag
So, "Why does git sign with GPG keys rather than using SSH keys?": it is what GPG is meant to do, as opposed to SSH, which cannot do with openssh alone (it needs openssl).
As commented by torek, using SSH would be theoretically possible, it's just not convenient.
In addition, PGP has extra features (not that Git uses them directly—Git itself is just invokes some external software—but things like key revocation are useful in these contexts).
With Git 2.37 (Q3 2022) explains ssh.defaultKeyCommand:
See commit ce18a30 (08 Jun 2022) by Fabian Stelzer (FStelzer).
(Merged by Junio C Hamano -- gitster -- in commit 686790f, 15 Jun 2022)
gpg docs: explain better use of ssh.defaultKeyCommand
Signed-off-by: Fabian Stelzer
Using ssh-add -L for gpg.ssh.defaultKeyCommand is not a good recommendation.
It might switch keys depending on the order of known keys and it only supports ssh-* and no ecdsa or other keys.
Clarify that we expect a literal key prefixed by key::, give valid example use cases and refer to user.signingKey as the preferred option.
git config now includes in its man page:
signature is requested. On successful exit a valid ssh public key
prefixed with key:: is expected in the first line of its output.
This allows for a script doing a dynamic lookup of the correct public
key when it is impractical to statically configure user.signingKey.
For example when keys or SSH Certificates are rotated frequently or
selection of the right key depends on external factors unknown to git.
And, with commit ce18a30 (08 Jun 2022) by Fabian Stelzer (FStelzer).
(Merged by Junio C Hamano -- gitster -- in commit 686790f, 15 Jun 2022)
686790f6c1:Merge branch 'fs/ssh-default-key-command-doc'
Doc update: fs/ssh-default-key-command-doc: gpg docs: explain better use of ssh.defaultKeyCommand
gpg.ssh.defaultKeyCommand:
This command that will be run when user.signingkey is not set and a ssh signature is requested.
On successful exit a valid ssh public key prefixed with key:: is expected in the first line of its output.
This allows for a script doing a dynamic lookup of the correct public key when it is impractical to statically configure user.signingKey.
For example when keys or SSH Certificates are rotated frequently or selection of the right key depends on external factors unknown to git.
The reason why you should NOT use ssh for signing commits is the one of the common rules of cryptography: You should not use the same keys for different applications/use cases.
In SSH you use a key for authentication, but that is something different then the signing your commits. For this, GPG is much more suited as it is already widely used for signing emails, files and so on.
One likely reason is that not everybody using git is using ssh.
You can create a git repo and never have it leave your local disk. You can use the git protocol, or http, or https, or network filesystems... none of those things involve ssh, but you can still sign commits, because that happens independent of any network transport or other push/pull sharing of your commits.
FWIW, work is underway to allow the use of SSH keys for signature (and verification): https://lore.kernel.org/git/pull.1041.git.git.1625559593910.gitgitgadget#gmail.com/
This will presumably be valuable in limited (eg corporate) contexts where git is currently the only reason to deal with GPG, and sticking with SSH only could save some key-management and software-management overhead for users...

How does one use the .sig file for these Renderdoc Windows builds?

For verifying builds of Renderdoc using the publisher's public key, verifying the Linux binary tarball works as expected; I run gpg --import ./baldurk-pubkey.asc and then gpg --verify renderdoc_1.18.tar.gz.sig renderdoc_1.18.tar.gz and then I receive the following output:
gpg: Signature made Tue Jan 25 07:25:56 2022 MST
gpg: using RSA key 1B039DB9A4718A2D699DE031AC612C3120C34695
gpg: Good signature from "Baldur Karlsson <baldurk#baldurk.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 1B03 9DB9 A471 8A2D 699D E031 AC61 2C31 20C3 4695
However, when I try to do the same process for the Windows 64-bit portable zip, i.e. gpg --verify RenderDoc_1.18_64.zip.sig RenderDoc_1.18_64.zip I receive the following output instead:
gpg: Signature made Tue Jan 25 08:01:06 2022 MST
gpg: using RSA key EC0F4688931695D3BCF0D10FB93B9B66E68BA2E9
gpg: Can't check signature: No public key
I receive similar output if I attempt to pass in the extracted qrenderdoc.exe as the second argument instead of the .zip itself.
I understand that the Windows executables have their own digital signatures; if I right-click qrenderdoc.exe, go to "Properties", and then go to the "Digital Signatures" tab, there is a signature by the same publisher. But I am confused as to what purpose the Windows .sig files serve or how to use them. I'm assuming there must be a correct way to do this, or else the sig files would not be provided, but I do not know what that way would be.
OK, I can sort of understand the downvote to my question. Clearly, as the output to the command for the .zip.sig says, it was signed with a different RSA key. I assumed that, since the Renderdoc website makes no mention of another key and nobody else online mentioned any issues with the Renderdoc signatures, then clearly there was an obvious way to find/add said key that I was missing. But after asking the developer, it turns out they changed build systems at some point and a different key was being used, and I guess I was just the first one to notice or report the problem. I can see now that this probably should have been my first assumption; apologies for the unnecessary question.
In the miniscule chance another Renderdoc user stumbles across this: According to the developer, subsequent builds (so anything above the current v1.18) will be signed with the correct key.

Differences in behavior for different openssl versions

I'm not sure what I'm doing wrong here, but I've got all of my passwords saved in a file as encrypted strings. The command I use to encrypt them is something like:
echo "password" | openssl enc -aes-256-cbc -a -nosalt
I then use password as the encryption key.
Originally (using openssl version 1.0.2g), this resulted in the string
7Lz5dLLYCLCv9GjadL1LTQ==
which has been saved to the passwords file. However, when I now run the same command using version 1.1.0g, I get the string
qq26+CHHB6MuY33GAqeIVw==
This means that when I now come to decode my passwords, they do not decode correctly. Is there something that I'm missing here?
NB: I know that the nosalt option is a bad idea, and I don't actually use it. I've just included it here to help clarify my problem.
The default hash used to generate the encryption key from the password changed between OpenSSL 1.0.2 and OpenSSL 1.1.0.
See this FAQ entry:
https://www.openssl.org/docs/faq.html#USER3
In 1.0.2 the default hash is md5, in 1.1.0 it is sha256. Specify the hash you want to use with the "-md" option.

Verifying a signature with an explicitly given public key

Suppose you want to distribute a file foo along with its detached signature foo.sig and your public key public.key.
Suppose further you want to make signature verification as easy as possible, i.e. in the minimum number of steps: just one command. Ideally something like
gpg2 [magic option combo here involving foo, foo.sig, public.key]
I've read the gpg2 man page up and down a few times, but it seems the receiver needs to first import the public key to his key ring.
Is there a way to avoid importing the public key and specify it explicitly? I would like to avoid the receiver being spammed with a newly created $HOME/.gnupg directory and its contents.
Or am I trying something stupid from a security point of view?
Use gpgv instead, which you can pass a keyring file (a single exported key also accounts as a keyring). If no slash is contained in the keyring path, gpgv will search in the GnuPG home directory, so either pass an absolute path or at least include ./ to denote the current working directory if no slash would be involved otherwise:
# Create and sign file
echo foo >foo.txt
gpg --local-user a4ff2279 --sign foo.txt
# Create "keyring" / export key
gpg --export a4ff2279 >a4ff2279.gpg
# Verify using gpgv
gpgv --keyring ./a4ff2279.gpg foo.txt.gpg
Finally, the only difference between importing and not importing the key is whether how the key is verified. There is no verification through the web of trust, certifications and local trust if you don't import the key, if the only way to verify the key is "downloading it from a trusted source", not importing it is totally fine. If you just fetch file, signature and key from an untrusted web server without encrypted connection and certificate, the OpenPGP signature is degraded to a simple checksum to realize transmission errors, not attacks providing faked files, signatures and keys.

public and private key files (.pkr,.skr)

i am new to PGP and want to implement encryption/decryption in one requirement. i googled it and decided to use Boynce Castle algo. But when i am trying to understand it, i confused at how i will get the .pkr and .skr files. i just downloaded required jars and program and when tried to run it shows me file not found. i was not aware so by myself i created .pkr and .skr files (converting from .txt) but i think it should be in some format and that should generated by some mechanism. can some explain me about this? How i can proceed.. ?
If you have PGP Desktop installed on the same Windows computer as the PGP Command Line, and you installed PGP Desktop to the default directory, then PGP Command Line will automatically locate and use your existing keyrings. If you are not using PGP Keyrings from a PGP Desktop product, you will need to create blank keyring files. To do so open a command prompt and type the following command:
pgp --create-keyrings
This will create a pubring.pkr (public keyring) and secring.skr (private keyring) file in the default keyring location. For Windows this is in the My Documents>PGP folder. This article will use [ ] to identify information that you will need to enter that is specific to your individual keys.
After that, you will need to create a key pair. To create a key pair using PGP Command Line follow these steps:
On the command line, enter:
pgp --gen-key [user ID] --key-type [key type] --bits [bits #] --passphrase [passphrase]
NOTE: Any information that contains spaces must be contained inside quotation marks.
Example: The following example will show you how to create a 2048 Bit RSA key for Joe User, an employee of ACME Corp, with the passphrase "my passphrase".
pgp --gen-key "Joe User" --key-type RSA --bits 2048 --passphrase "my passphrase"
PGP Command line will now generate your keypair. You should see your Key ID (i.e. 0X12345678), and a message that the key was successfully generated.
NOTE: To display your new keypair enter the following command:
pgp --list-keys
This will display all the keys that are found on your keyring.
After the key pair is generated and identified, it is important to export the public portion (public key) of the key pair so others can import your public key and encrypt to you. NOTES: Once you have exported your public key to a file, it is easy to distribute. You can attach it to an email, paste the public key block text into the body of an email message (open with Notepad), or copy to a CD, for example. To export your public key you will need to have information about the key in order to identify it, which will be referred to in this document as (input). You can use the key ID (i.e. 0x12345678), user ID (i.e. "Joe User"), or a portion of the user ID, (i.e. Joe). To export the key, do the following:
pgp --export (input)
PGP Command Line responds by exporting keys as ASCII armor (.asc) files into the directory currently active on the command line.
The following examples will show you how to export your public key using your key ID and user ID.
pgp --export 0x12345678
pgp --export "Joe User"
You may import a public key from an ASCII Armor file (.asc) or from a text file, the process is the same for both. The file containing the key(s) to be imported must be in the current directory. As with exporting a key, this will be referred to as (input) in the examples. Both public and private keys will be imported if they exist in the file. If a key being imported already exists in the local keyring, the keys are merged. Import Key From File:
pgp --import (input)
PGP Command Line responds as follows: Joe User.asc:import key {0:key imported as 0x12345678 Joe User}
The following examples will show you how to import a key from an ASCII Armor file (.asc) and from a text file containing the PGP key block.
pgp --import "Joe User.asc"
pgp --import "PGP Joe.txt"
Those files are public and private (secret in OpenPGP terminology) keyrings respectively. They contain collections of public and private keys. You usually generate a keypair (a pair of public and private key) or several keypairs for your own use, and other people do the same. Then they can give you their public keys and you create a public keyring from those keys. Public keyring is then used to encrypt data for recipients or to verify other people's daa signatures.
Private keyring is composed from your private keys which you generate. You use private keyring for signing your data, and you can give corresponding public keys to other people so that they could encrypt data for you (which you then decrypt using your private keys).
I believe BouncyCastle has key generation functions, or you can use GnuPG application or PGP Desktop to generate keys.
You can check the examples for OpenPGP key generation that ship with the BouncyCastle library.
They are located at :
[bouncy castle sources]\src\org\bouncycastle\openpgp\examples\RSAKeyPairGenerator.java
[bouncy castle sources]\src\org\bouncycastle\openpgp\examples\DSAElGamalKeyRingGenerator.java
Example code that uses the keys can be found at:
[bouncy castle sources]\src\org\bouncycastle\openpgp\examples\KeyBasedFileProcessor.java

Resources