PGP file decryption\ - go

I am looking for suggestions on how to use openPGP to decrypt a PGP encrypted file we receive externally. The file is placed on a Google Cloud bucket and I am planning to use a Cloud function to run the decryption.
There are several examples (this and this) on the web with Go and OpenPGP but they are limited to decrypting strings/texts and not files. The file is encrypted using a traditional PGP encrypt command.
I am trying to avoid creating a VM or asking the external agency to change the encryption process.

In your example linked you can see that it decrypts a byte slice []byte. It can be the content from an encrypted file.
You can replace the
decrypted, err := pgp.Decrypt(privEntity, encrypted)
if err != nil {
t.Error(err)
}
by
encrypted, err := ioutil.ReadFile(filename)
if err != nil {
t.Error(err)
}
decrypted, err := pgp.Decrypt(privEntity, encrypted)
if err != nil {
t.Error(err)
}

Related

What is privatekey in oracle objectstorage?

c, clerr := objectstorage.NewObjectStorageClientWithConfigurationProvider(common.NewRawConfigurationProvider(
"ocid1.tenancy.oc1..aaaaaaa5jo3pz1alm1o45rzx1ucaab4njxbwaqqbc7ld3l6biayjaert5la",
"ocid1.user.oc1..aaaaaaaauax5bo2gg3az46h53467u57ue86rk9h2wax8w7zzamxgwvsi34ja",
"ap-seoul-1",
"98:bc:6b:13:c1:64:ds:8b:9c:15:11:d2:8d:e5:92:db",
))
I'm trying to use oracle object storage, I checked the official manual, but there is something I don't understand. As above, I need the privateKey, and pricateKeyPassphrase arguments, but I don't know where to get them. Is there a detailed explanation or example?
What i want, is to upload a file to storage.
Where can I go to the page in the oracle console to get the keys I need? please give me some advice
config, err := common.ConfigurationProviderFromFile("./config", "")
if err != nil {
t.Error(err.Error())
}
c, err := objectstorage.NewObjectStorageClientWithConfigurationProvider(config)
if err != nil {
t.Error(err.Error())
}
https://cloud.oracle.com/identity/domains/my-profile/api-keys
I generated a key on this page, put it in my project, and with the above code I was able to get started without any problems.

What is the best way to deal with plain text passwords in Go

I'm creating a simple program to register my IP to OpenDNS when it changes. I know about the ddclient but I want to write my own just for learning purposes.
To be able to perform any operation on OpenDNS, I have to call the URL specifying my user and pass, so a curl example would be something like: curl -u user:password https://updates.opendns.com/nic/update?hostname=xxxx&myip=123.123.123.123
In Go I created the following function:
func registerNewIpToOpenDns(ip string) (int, error) {
openDnsURL := "https://updates.opendns.com/nic/update?hostname=xxxx&myip=" + ip
req, err := http.NewRequest("GET", openDnsURL, nil)
if err != nil {
return 0, err
}
req.SetBasicAuth("USER", "PASS")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return 0, err
}
defer resp.Body.Close()
return resp.StatusCode, nil
}
So how should I perform the input of the user/pass to this program? I will let this project 'Public' in Github.
I was thinking in creating a file something like "input" and add it to .gitignore.
So if someone else wants to use the program, the person would just need to create it own "input" file and the program would read from it.
What do you think?
Put the configuration data that wouldn't be true for everybody in environment variables.
Use os.Getenv() to retrieve the variables at runtime. Make sure they are set to something valid looking (at least not empty string) as part of your program's configuration.
You can then set the environment variables in a systemd configuration file if you're running this from systemd, or in the .bash_config for a user dedicated to this process, or wherever is the most convenient for where your program is executed.
Or, create a configuration file you can read from your program. I usually use Json encoding for configuration like this, but you could use anything. Reading secrets from configuration files might arguably be somewhat safer than environment variables which can often be introspected by system processes.
When I create a configuration file, I usually model my configuration with a struct,
type Config struct {
Username string
Password string
}
Then as part of my program's initialization, I'd do something like
const ConfigFileEnv "ConfigFile" // avoid typing errors
var config Config
...
if f, err := os.Open(os.Getenv(ConfigFileEnv); err != nil {
panic(fmt.Errorf("Couldn't open config file %s: %w",
os.Getenv(ConfigFileEnv),
err,
))
} else if err := json.NewDecoder(f).Decode(&config); err != nil {
panic(fmt.Errorf("Couldn't decode json from config file %s: %w",
os.Getenv(ConfigFileEnv),
err
)
}
// Now config file has been loaded into config
...
req.SetBasicAuth(config.Username, config.Password)
Working minimal example (without your logic): https://github.com/farrellit/stackoverflow/tree/main/69335827

How to handle chunked file upload

I'm creating a simple application where it allows users to upload big files using simple-uploader since this plugin sends the files in chunks instead of one big file. The problem is that when I save the file the first chunk is the only one that is being saved. Is there a way in Go where I'll wait for all the chunks to arrive in the server then save it afterward?
Here's a snippet of the code I'm doing:
dFile, err := c.FormFile("file")
if err != nil {
return SendError(c, err)
}
filename := dFile.Filename
f, err := dFile.Open()
if err != nil {
return SendError(c, err)
}
defer f.Close()
// save file in s3
duration := sss.UploadFile(f, "temp/"+filename")
... send response
By the way for this project, I'm using the fiber framework.
While working on this I encountered tus-js-client which is doing the same as the simple-uploader and implementation in go called tusd which will reassemble the chunks so you don't have to worry about it anymore.
Here's a discussion where I posted my solution: https://stackoverflow.com/a/65785097/549529.

Best pattern to create sha256 from file and store file

I am writing a webserver that receives a file as an upload as multipart/form-data. I am generating the file sha256 from the request but due to the nature of the Reader interface, I can't reuse the data to also upload the file to a filer. These files can be a few hundred MBs. What is the best way to store the content? I can duplicate the contents but I am worried that could be wasteful on memory resources.
EDIT
func uploadFile(w http.ResponseWriter, r *http.Request) {
f, err := r.MultipartForm.File["capture"][0].Open()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer f.Close()
hash, err := createSha(f)
if err != nil {
fmt.Println(err.Error())
return
}
}
func createSha(image multipart.File) (hash.Hash, error) {
sha := sha256.New()
// This cause the contents of image to no longer be available to be read again to be stored on the filer
if _, err := io.Copy(sha, image); err != nil {
return nil, err
}
return sha, nil
}
You might use io.MultiWriter(...) to send the data to multiple output streams concurrently, such as a hash and some remote writer.
For example (roughly):
sha := sha256.New()
filer := filer.New(...) // Some Writer that stores the bytes for you?
err := io.Copy(io.MultiWriter(sha, filer), r)
// TODO: handle error
// Now sha.Sum(nil) has the file digest and "filer" got sent all the bytes.
Note that io.Multiwriter can take as many writers as you want, so you could compute additional hashes at the same time (e.g. md5, sha1, etc.) or even send the file to multiple locations, e.g.:
md5, sha1, sha256, sha512 := md5.New(), sha1.New(), sha256.New(), sha512.New()
s3Writer, gcsWriter := filer.NewS3Writer(), filer.NewGCSWriter()
mw := io.MultiWriter(awsWriter, gcsWriter, md5, sha1, sha256, sha512)
err := io.Copy(mw, r)
// TODO: handle error
// Now you've got all the hashes for the file and it's stored in the cloud.

How to Encrypt a String to an ASCII armored file in go

I'm at the moment realy struggeling in finding the error in my code - the task is to encrypt a string into a pgp ASCII armored file - a simple thing one could think.
I use the following function, inspired by this gist:
// pgp encryption using the pgp RSA certificate
// massive thx to https://gist.github.com/jyap808/8250124
func encToFile(secretString string, filename string) (string, error) {
log.Println("Public Keyring: ", publicKeyring)
encryptionType := "PGP MESSAGE"
// Read in public key
keyringFileBuffer, _ := os.Open(publicKeyring)
defer keyringFileBuffer.Close()
entityList, err := openpgp.ReadArmoredKeyRing(keyringFileBuffer)
check(err)
encbuf := bytes.NewBuffer(nil)
w, err := armor.Encode(encbuf, encryptionType, nil) // the encoder somehow makes this into ASCII armor
check(err)
plaintext, err := openpgp.Encrypt(w, entityList, nil, nil, nil)
check(err)
message := []byte(secretString)
_, err = plaintext.Write(message)
plaintext.Close()
w.Close()
// Output encrypted/encoded string
log.Println("Writing Encrypted Secred to: ", filename)
// we write the file into a file
err = ioutil.WriteFile(filename, encbuf.Bytes(), 0644)
check(err)
log.Println("File:\n", encbuf.String())
return encbuf.String(), nil
}
However, the guys on the other end get this error message:
gpg: encrypted with RSA key, ID 5BE299DC
gpg: decryption failed: No secret key
Hints and suggestion would be very welcome!
However, the guys on the other end get this error message:
gpg: encrypted with RSA key, ID 5BE299DC
gpg: decryption failed: No secret key
If you encrypted for the right key, I don't think you did anything wrong. Looking at that key on the key servers, you encrypted to the newest (and only) encryption subkey.
If the "guy on the other end" gets an error message indicating that he would not hold the secret key, then either
you use the wrong key for encryption,
"the other guy" gave you the wrong key or
"the other guy" messed up himself.
You can verify what's going wrong by passing the encrypted contents to gpg --list-packets or pgpdump, which list the OpenPGP packets contained in the message and are very helpful at debugging OpenPGP issues.

Resources