I'm trying to understand how encryption using the CTR mode works, so I created these functions to test it:
import (
"crypto/cipher"
"crypto/rand"
)
// generateIV generates an initialization vector (IV) suitable for encryption.
//
// http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Initialization_vector_.28IV.29
func generateIV(bytes int) []byte {
b := make([]byte, bytes)
rand.Read(b)
return b
}
func encrypt(block cipher.Block, value []byte) []byte {
iv := generateIV(block.BlockSize())
encrypted := make([]byte, len(value) + block.BlockSize())
encrypted = append(encrypted, iv...)
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(encrypted, value)
return encrypted
}
func decrypt(block cipher.Block, encrypted []byte) []byte {
iv := encrypted[:block.BlockSize()]
ciphertext := encrypted[block.BlockSize():]
stream := cipher.NewCTR(block, iv)
plain := make([]byte, len(ciphertext))
// XORKeyStream is used to decrypt too?
stream.XORKeyStream(plain, ciphertext)
return plain
}
Encryption seems to work fine, but well I don't know really because I don't understand the output of decryption. Should I use stream.XORKeyStream to decrypt too? The test looks like this:
import (
"crypto/aes"
"fmt"
"testing"
)
func TestEncryptCTR(t *testing.T) {
block, err := aes.NewCipher([]byte("1234567890123456"))
if err != nil {
panic(err)
}
value := "foobarbaz"
encrypted := encrypt(block, []byte(value))
decrypted := decrypt(block, encrypted)
fmt.Printf("--- %s ---", string(decrypted))
}
But I'm definitely not getting "foobarbaz" back. Can you spot what I'm doing wrong?
The problem was me trying to do too much before testing the basics. I wanted to prepend the IV to the generated ciphertext, but somewhat I broke everything when I did that. This simple version, with no prepended IV, works:
import (
"crypto/cipher"
"crypto/rand"
)
// generateIV generates an initialization vector (IV) suitable for encryption.
//
// http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Initialization_vector_.28IV.29
func generateIV(bytes int) []byte {
b := make([]byte, bytes)
rand.Read(b)
return b
}
func encrypt(block cipher.Block, value []byte, iv []byte) []byte {
stream := cipher.NewCTR(block, iv)
ciphertext := make([]byte, len(value))
stream.XORKeyStream(ciphertext, value)
return ciphertext
}
func decrypt(block cipher.Block, ciphertext []byte, iv []byte) []byte {
stream := cipher.NewCTR(block, iv)
plain := make([]byte, len(ciphertext))
// XORKeyStream is used to decrypt too!
stream.XORKeyStream(plain, ciphertext)
return plain
}
And the corresponding test:
import (
"crypto/aes"
"fmt"
"testing"
)
func TestEncryptCTR(t *testing.T) {
block, err := aes.NewCipher([]byte("1234567890123456"))
if err != nil {
panic(err)
}
iv := generateIV(block.BlockSize())
value := "foobarbaz"
encrypted := encrypt2(block, []byte(value), iv)
decrypted := decrypt2(block, encrypted, iv)
fmt.Printf("--- %s ---", string(decrypted))
}
I get "--- foobarbaz ---", as expected.
Now back to make the prepending IV work. :)
Edit And this is it, with auto-generated and prepended IV:
func encrypt(block cipher.Block, value []byte) []byte {
// Generate an initialization vector (IV) suitable for encryption.
// http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Initialization_vector_.28IV.29
iv := make([]byte, block.BlockSize())
rand.Read(iv)
// Encrypt it.
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(value, value)
// Return iv + ciphertext.
return append(iv, value...)
}
func decrypt(block cipher.Block, value []byte) []byte {
if len(value) > block.BlockSize() {
// Extract iv.
iv := value[:block.BlockSize()]
// Extract ciphertext.
value = value[block.BlockSize():]
// Decrypt it.
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(value, value)
return value
}
return nil
}
Related
I couldn't find anything helpful online on this one.
I am writing an REST API, and I want to log the size of the body of the request in bytes for metrics. Go net/http API does not provide that directly. http.Request does have Content-Length field, but that field can be empty or the client might send false data.
Is there a way to get that in the middlware level? The bruteforce method would be to read the full body and check the size. But if I do that in the middleware, the handler will not have access to the body because it would have been read and closed.
Why do you want a middle in here?
The simple way is b, err = io.Copy(anyWriterOrMultiwriter, r.Body)
b is total content length of request when err == nil
Use request body as you want. Also b, err = io.Copy(ioutil.Discard, r.Body)
You could write a custom ReadCloser that proxies an existing one and counts bytes as it goes. Something like:
type LengthReader struct {
Source io.ReadCloser
Length int
}
func (r *LengthReader) Read(b []byte) (int, error) {
n, err := r.Source.Read(b)
r.Length += n
return n, err
}
func (r *LengthReader) Close() error {
var buf [32]byte
var n int
var err error
for err == nil {
n, err = r.Source.Read(buf[:])
r.Length += n
}
closeerr := r.Source.Close()
if err != nil && err != io.EOF {
return err
}
return closeerr
}
This will count bytes as you read them from the stream, and when closed it will consume and count all remaining unread bytes first. After you're finished with the stream, you can then access the length.
Option 1
Use TeeReader and this is scalable. It splits reader into two and one of them calculates the size using allocated memory. Also, in the first case
maxmem := 4096
var buf bytes.Buffer
// comment this line out if you want to disable gathering metrics
resp.Body = io.TeeReader(resp.Body, &buf)
readsize := func(r io.Reader) int {
bytes := make([]byte, maxmem)
var size int
for {
read, err := r.Read(bytes)
if err == io.EOF {
break
}
size += read
}
return size
}
log.Printf("Size is %d", readsize(&buf))
Option 2 unscalable way (original answer)
You can just read the body, calculate the size, then unmarshal into struct, so that it becomes:
b, _ := ioutil.ReadAll(r.Body)
size := len(b) // can be nil so check err in your app
if err := json.Unmarshal(b, &input); err != nil {
s.BadReq(w, errors.New("error reading body"))
return
}
My code:
func getSourceUrl(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
fmt.Println("Error getSourceUrl: ")
return "", err
}
defer resp.Body.Close()
body := resp.Body
// time = 0
sourcePage, err := ioutil.ReadAll(body)
// time > 5 minutes
return string(sourcePage), err
}
I have a website link with a source of around> 100000 lines. Using ioutil.ReadAll made me get very long (about> 5 minutes for 1 link). Is there a way to get Source website faster? Thank you!
#Minato try this code, play with M throttling parameter. Play with it if you get too errors (reduce it).
package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"runtime"
"time"
)
// Token is an empty struct for signalling
type Token struct{}
// N files to get
var N = 301 // at the source 00000 - 00300
// M max go routines
var M = runtime.NumCPU() * 16
// Throttle to max M go routines
var Throttle = make(chan Token, M)
// DoneStatus is used to signal end of
type DoneStatus struct {
length int
sequence string
duration float64
err error
}
// ExitOK is simple exit counter
var ExitOK = make(chan DoneStatus)
// TotalBytes read
var TotalBytes = 0
// TotalErrors captured
var TotalErrors = 0
// URLTempl is templte for URL construction
var URLTempl = "https://virusshare.com/hashes/VirusShare_%05d.md5"
func close(c io.Closer) {
err := c.Close()
if err != nil {
log.Fatal(err)
}
}
func main() {
log.Printf("start main. M=%d\n", M)
startTime := time.Now()
for i := 0; i < N; i++ {
go func(idx int) {
// slow ramp up fire getData after i seconds
time.Sleep(time.Duration(i) * time.Second)
url := fmt.Sprintf(URLTempl, idx)
_, _ = getData(url) // errors captured as data
}(i)
}
// Count N byte count signals
for i := 0; i < N; i++ {
status := <-ExitOK
TotalBytes += status.length
if status.err != nil {
TotalErrors++
log.Printf("[%d] : %v\n", i, status.err)
continue
}
log.Printf("[%d] file %s, %.1f MByte, %.1f min, %.1f KByte/sec\n",
i, status.sequence,
float64(status.length)/(1024*1024),
status.duration/60,
float64(status.length)/(1024)/status.duration)
}
// totals
duration := time.Since(startTime).Seconds()
log.Printf("Totals: %.1f MByte, %.1f min, %.1f KByte/sec\n",
float64(TotalBytes)/(1024*1024),
duration/60,
float64(TotalBytes)/(1024)/duration)
// using fatal to verify only one go routine is running at the end
log.Fatalf("TotalErrors: %d\n", TotalErrors)
}
func getData(url string) (data []byte, err error) {
var startTime time.Time
defer func() {
// release token
<-Throttle
// signal end of go routine, with some status info
ExitOK <- DoneStatus{
len(data),
url[41:46],
time.Since(startTime).Seconds(),
err,
}
}()
// acquire one of M tokens
Throttle <- Token{}
log.Printf("Started file: %s\n", url[41:46])
startTime = time.Now()
resp, err := http.Get(url)
if err != nil {
return
}
defer close(resp.Body)
data, err = ioutil.ReadAll(resp.Body)
if err != nil {
return
}
return
}
Per transfer variation is about 10-40KByte/sec and final total for all 301 files I get 928MB, 11.1min at 1425 KByte/sec. I believe you should be able to get similar results.
// outside the scope of the question but maybe useful
Also give this a try http://www.dslreports.com/speedtest/ go to settings and select bunch of US servers for testing and set duration to 60sec. This will tell you what your actual effective total rate is to US.
Good luck!
You could iterate sections of the response at a time, something like;
responseSection := make([]byte, 128)
body.Read(responseSection)
return string(responseSection), err
Which would read 128 bytes at a time. However would suggest confirming the download speed is not causing the slow load.
The 5 minutes is probably network time.
That said, you generally would not want to buffer enormous objects in memory.
resp.Body is a Reader.
So you cold use io.Copy to copy its contents into a file.
Converting sourcePage into a string is a bad idea as it forces another allocation.
I'm reading a JSON file that contains Unix Epoch dates, but they are strings in the JSON. In Go, can I convert a string in the form "1490846400" into a Go time.Time?
There is no such function in time package, but it's easy to write:
func stringToTime(s string) (time.Time, error) {
sec, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return time.Time{}, err
}
return time.Unix(sec, 0), nil
}
Playground: https://play.golang.org/p/2h0Vd7plgk.
There's nothing wrong, or incorrect about the answer provided by #Ainar-G, but likely a better way to do this is with a custom JSON unmarshaler:
type EpochTime time.Time
func (et *EpochTime) UnmarshalJSON(data []byte) error {
t := strings.Trim(string(data), `"`) // Remove quote marks from around the JSON string
sec, err := strconv.ParseInt(t, 10, 64)
if err != nil {
return err
}
epochTime := time.Unix(sec,0)
*et = EpochTime(epochTime)
return nil
}
Then in your struct, replace time.Time with EpochTime:
type SomeDocument struct {
Timestamp EpochTime `json:"time"`
// other fields
}
I'm trying to send a int64 over a TCP in golang, however, my receiver prints gets a different number then what I've sent out. What is the proper way to accomplish this?
//Buffer on both client and server
buffer := make([]byte, 1024)
//Sender
fileInfo, error := os.Stat(fileName)
if error != nil {
fmt.Println("Error opening file")
}
var fSize int = int(fileInfo.Size())
connection.Write([]byte(string(fSize)))
//Receiver
connection.Read(buffer)
fileSize := new(big.Int).SetBytes(bytes.Trim(buffer, "\x00")).Int64()
if err != nil {
fmt.Println("not a valid filesize")
fileSize = 0
}
Using binary.Write / binary.Read:
//sender
err := binary.Write(connection, binary.LittleEndian, fileInfo.Size())
if err != nil {
fmt.Println("err:", err)
}
//receiver
var size int64
err := binary.Read(connection, binary.LittleEndian, &size)
if err != nil {
fmt.Println("err:", err)
}
[]byte(string(fSize)) doesn't do what you think it does, it treats the number as unicode character, it doesn't return the string representation of it.
If you want the string representation of a number, use strconv.Itoa, if you want the binary represention then use:
num := make([]byte, 8) // or 4 for int32 or 2 for int16
binary.LittleEndian.PutUint64(num, 1<<64-1)
Use binary.BigEndian or binary.LittleEndian to encode the integer:
var size int64
// Send
var buf [8]byte
binary.BigEndian.PutUint64(buf[:], uint64(size))
_, err := w.Write(buf[:])
// Receive
var buf [8]byte
_, err := io.ReadFull(r, buf[:])
if err != nil {
// handle error
}
size = int64(binary.BigEndian.Uint64(buf[:])
You can also use the binary.Read and binary.Write. Your application code will be a little shorter at the cost of type switches and other goo inside these functions.
A couple of points about the code in the question. The conversion
string(fSize)
returns the UTF-8 representation of the rune fSize. It does not return a decimal encoding or binary encoding the value. Use the strconv packate to convert a numeric value to a decimal representation. Use the above mentioned binary package to convert to binary representation.
The sequence
connection.Read(buffer)
buffer = bytes.Trim(buffer, "\x00")
trims away real data if the data happens to include a 0 byte at the ends. Read returns the number of bytes read. Use that length to slice the buffer:
n, err := connection.Read(buffer)
buffer = buffer[:n]
You can't use string() to cast from an int, you need to use the strconv package.
connection.Write([]byte(strconv.FormatInt(fileInfo.Size(), 10))
So I'm pretty new to golang and i'm struggling to get a working example going of encrypting some text with openpgp and decrypting it again.
Here is what I have so far: (https://gist.github.com/93750a142d3de4e8fdd2.git)
package main
import (
"log"
"bytes"
"code.google.com/p/go.crypto/openpgp"
"encoding/base64"
"io/ioutil"
"os"
)
// create gpg keys with
// $ gpg --gen-key
// ensure you correct paths and passphrase
const mysecretstring = "this is so very secret!"
const secretKeyring = "/Users/stuart-warren/.gnupg/secring.gpg"
const publicKeyring = "/Users/stuart-warren/.gnupg/pubring.gpg"
const passphrase = "1234"
func main() {
log.Printf("Secret: ", mysecretstring)
log.Printf("Secret Keyring: ", secretKeyring)
log.Printf("Public Keyring: ", publicKeyring)
log.Printf("Passphrase: ", passphrase)
// Read in public key
keyringFileBuffer, _ := os.Open(publicKeyring)
defer keyringFileBuffer.Close()
entitylist, _ := openpgp.ReadKeyRing(keyringFileBuffer)
// encrypt string
buf := new(bytes.Buffer)
w, _ := openpgp.Encrypt(buf, entitylist, nil, nil, nil)
w.Write([]byte(mysecretstring))
// Encode to base64
bytesp, _ := ioutil.ReadAll(buf)
encstr := base64.StdEncoding.EncodeToString(bytesp)
// Output encrypted/encoded string
log.Printf("Encrypted Secret: ", encstr)
// Here is where I would transfer the encrypted string to someone else
// but we'll just decrypt it in the same code
// init some vars
var entity2 *openpgp.Entity
var entitylist2 openpgp.EntityList
// Open the private key file
keyringFileBuffer2, _ := os.Open(secretKeyring)
defer keyringFileBuffer2.Close()
entitylist2, _ = openpgp.ReadKeyRing(keyringFileBuffer2)
entity2 = entitylist2[0]
// Get the passphrase and read the private key.
// Have not touched the encrypted string yet
passphrasebyte := []byte(passphrase)
log.Printf("Decrypting private key using passphrase")
entity2.PrivateKey.Decrypt(passphrasebyte)
for _, subkey := range entity2.Subkeys {
subkey.PrivateKey.Decrypt(passphrasebyte)
}
log.Printf("Finished decrypting private key using passphrase")
// Decode the base64 string
dec, _ := base64.StdEncoding.DecodeString(encstr)
// Decrypt it with the contents of the private key
md, _ := openpgp.ReadMessage(bytes.NewBuffer(dec), entitylist2, nil, nil)
bytess, _ := ioutil.ReadAll(md.UnverifiedBody)
decstr := string(bytess)
// should be done
log.Printf("Decrypted Secret: ", decstr)
}
This is based off of https://github.com/jyap808/jaeger
When I run it, it seems to partially work, but only outputs some of the characters of the original string... Changing the original string causes some very weird issues.
2014/09/07 22:59:38 Secret: %!(EXTRA string=this is so very secret!)
2014/09/07 22:59:38 Secret Keyring: %!(EXTRA string=/Users/stuart-warren/.gnupg/secring.gpg)
2014/09/07 22:59:38 Public Keyring: %!(EXTRA string=/Users/stuart-warren/.gnupg/pubring.gpg)
2014/09/07 22:59:38 Passphrase: %!(EXTRA string=1234)
2014/09/07 22:59:38 Encrypted Secret: %!(EXTRA string=wcBMA5a76vUxixWPAQgAOkrt/LQ3u++VbJ/20egxCUzMqcMYtq+JXL7SqbB5S1KrgHhGd8RHUmxy2h45hOLcAt+kfvSz0EJ/EsCmwnbP6HRPEqiMLt6XaVS26Rr9HQHPpRBZkqnwAP0EmlYNnF5zjnU5xTcEOyyr7EYhEgDv0Ro1FQkaCL2xdBhDCXs4EdQsjVrcECWOt0KgbCWs+N/0cEdeyHwodkaDgJ7NMq/pPuviaRu4JHCIxMiyz8yhOCHOM+bI80KsJesjGrgbjnGDfJUZNYDBNc8PqzfC39lB2MBrn/w07thJxvjbep39R0u2C4eEcroTRLB+t9i4fJNiVpoSclYRSZXm5OsYYv/XwtLgAeRZ07lFEsGoHSbqGLUnHFFw4Svk4FPgCuGVpOCS4vYiisDg+ORYj8dpu/Z3gSlVJ6mhSr7H4J3i9vItRuBx4WUB4HHgmQ==)
2014/09/07 22:59:38 Decrypting private key using passphrase
2014/09/07 22:59:38 Finished decrypting private key using passphrase
2014/09/07 22:59:38 Decrypted Secret: %!(EXTRA string=this)
Clearly there is something I'm not understanding, so would appreciate any assistance given.
A reminder that security is unusually treacherous territory, and if there's a way to call on other well-tested code even more of your toplevel task than just what Go's OpenPGP package is handling for you, consider it. It's good that at least low-level details are outsourced to openpgp because they're nasty and so so easy to get wrong. But tiny mistakes at any level can make crypto features worse than useless; if there's a way to write less security-critical code, that's one of the best things anyone can do for security.
On the specific question: you have to Close() the writer to get everything flushed out (a trait OpenPGP's writer shares with, say, compress/gzip's).
Unrelated changes: the way you're printing things is a better fit log.Println, which just lets you pass a bunch of values you want printed with spaces in between (like, say, Python print), rather than needing format specifiers like "%s" or "%d". (The "EXTRA" in your initial output is what Go's Printf emits when you pass more things than you had format specifiers for.) It's also best practice to check errors (I dropped if err != nils where I saw a need, but inelegantly and without much thought, and I may not have gotten all the calls) and to run go fmt on your code.
Again, I can't testify to the seaworthiness of this code or anything like that. But now it round-trips all the text. I wound up with:
package main
import (
"bytes"
"code.google.com/p/go.crypto/openpgp"
"encoding/base64"
"io/ioutil"
"log"
"os"
)
// create gpg keys with
// $ gpg --gen-key
// ensure you correct paths and passphrase
const mysecretstring = "this is so very secret!"
const prefix, passphrase = "/Users/stuart-warren/", "1234"
const secretKeyring = prefix + ".gnupg/secring.gpg"
const publicKeyring = prefix + ".gnupg/pubring.gpg"
func encTest() error {
log.Println("Secret:", mysecretstring)
log.Println("Secret Keyring:", secretKeyring)
log.Println("Public Keyring:", publicKeyring)
log.Println("Passphrase:", passphrase)
// Read in public key
keyringFileBuffer, _ := os.Open(publicKeyring)
defer keyringFileBuffer.Close()
entitylist, err := openpgp.ReadKeyRing(keyringFileBuffer)
if err != nil {
return err
}
// encrypt string
buf := new(bytes.Buffer)
w, err := openpgp.Encrypt(buf, entitylist, nil, nil, nil)
if err != nil {
return err
}
_, err = w.Write([]byte(mysecretstring))
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
// Encode to base64
bytesp, err := ioutil.ReadAll(buf)
if err != nil {
return err
}
encstr := base64.StdEncoding.EncodeToString(bytesp)
// Output encrypted/encoded string
log.Println("Encrypted Secret:", encstr)
// Here is where I would transfer the encrypted string to someone else
// but we'll just decrypt it in the same code
// init some vars
var entity2 *openpgp.Entity
var entitylist2 openpgp.EntityList
// Open the private key file
keyringFileBuffer2, err := os.Open(secretKeyring)
if err != nil {
return err
}
defer keyringFileBuffer2.Close()
entitylist2, err = openpgp.ReadKeyRing(keyringFileBuffer2)
if err != nil {
return err
}
entity2 = entitylist2[0]
// Get the passphrase and read the private key.
// Have not touched the encrypted string yet
passphrasebyte := []byte(passphrase)
log.Println("Decrypting private key using passphrase")
entity2.PrivateKey.Decrypt(passphrasebyte)
for _, subkey := range entity2.Subkeys {
subkey.PrivateKey.Decrypt(passphrasebyte)
}
log.Println("Finished decrypting private key using passphrase")
// Decode the base64 string
dec, err := base64.StdEncoding.DecodeString(encstr)
if err != nil {
return err
}
// Decrypt it with the contents of the private key
md, err := openpgp.ReadMessage(bytes.NewBuffer(dec), entitylist2, nil, nil)
if err != nil {
return err
}
bytess, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
return err
}
decstr := string(bytess)
// should be done
log.Println("Decrypted Secret:", decstr)
return nil
}
func main() {
err := encTest()
if err != nil {
log.Fatal(err)
}
}
I cannot test your code, but the only thing i can think off, is that the order of execution is wrong. You first make a string, then you make it Base64, then you encrypt it. Now you undo the Base64 and afterwards you decrypt the encoded string. These last two must be swapped.