func forwardData(conn net.Conn, data []byte, stream cipher.Stream) (n int, err error) { left := len(data) % 16 first := len(data) - left n1 := 0 if first != 0 { dst := make([]byte, 8+first) binary.BigEndian.PutUint32(dst, uint32(first)) binary.BigEndian.PutUint32(dst[4:], uint32(first)) stream.XORKeyStream(dst[8:], data[0:first]) n1, err = conn.Write(dst) if err != nil { return n1, err } } n2 := 0 if left != 0 { src := make([]byte, 16) dst := make([]byte, 8+16) copy(src, data[first:]) binary.BigEndian.PutUint32(dst, uint32(left)) binary.BigEndian.PutUint32(dst[4:], uint32(16)) stream.XORKeyStream(dst[8:], src) n2, err = conn.Write(dst) if err != nil { return n2, err } } return n1 + n2, err }
// Try to generate a point on this curve from a chosen x-coordinate, // with a random sign. func (p *curvePoint) genPoint(x *big.Int, rand cipher.Stream) bool { // Compute the corresponding Y coordinate, if any y2 := new(big.Int).Mul(x, x) y2.Mul(y2, x) threeX := new(big.Int).Lsh(x, 1) threeX.Add(threeX, x) y2.Sub(y2, threeX) y2.Add(y2, p.c.p.B) y2.Mod(y2, p.c.p.P) y := p.c.sqrt(y2) // Pick a random sign for the y coordinate b := make([]byte, 1) rand.XORKeyStream(b, b) if (b[0] & 0x80) != 0 { y.Sub(p.c.p.P, y) } // Check that it's a valid point y2t := new(big.Int).Mul(y, y) y2t.Mod(y2t, p.c.p.P) if y2t.Cmp(y2) != 0 { return false // Doesn't yield a valid point! } p.x = x p.y = y return true }
func AesEncryptData(data, key []byte, ctp string) []byte { block, err := aes.NewCipher(key) if err != nil { return nil } // The IV needs to be unique, but not secure. Therefore it's common to // include it at the beginning of the ciphertext. data_enc := make([]byte, aes.BlockSize+len(data)) iv := data_enc[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil } var stream cipher.Stream switch ctp { case "cfb": stream = cipher.NewCFBEncrypter(block, iv) case "ctr": stream = cipher.NewCTR(block, iv) default: stream = cipher.NewOFB(block, iv) } stream.XORKeyStream(data_enc[aes.BlockSize:], data) // It's important to remember that ciphertexts must be authenticated // (i.e. by using crypto/hmac) as well as being encrypted in order to // be secure. return data_enc }
func (s *secret) Pick(rand cipher.Stream) abstract.Secret { rand.XORKeyStream(s.b[:], s.b[:]) s.b[0] &= 248 s.b[31] &= 63 s.b[31] |= 64 return s }
func AESEncrypt(s string, key string) (c string, err error) { var k []byte var block cipher.Block var cfb cipher.Stream var cb []byte var iv []byte k = AESMake256Key(key) block, err = aes.NewCipher(k) if err != nil { return } cb = make([]byte, aes.BlockSize+len(s)) iv = cb[:aes.BlockSize] _, err = io.ReadFull(rand.Reader, iv) if err != nil { return } cfb = cipher.NewCFBEncrypter(block, iv) cfb.XORKeyStream(cb[aes.BlockSize:], bytes.NewBufferString(s).Bytes()) c = hex.EncodeToString(cb) return }
func (p *point) Pick(data []byte, rand cipher.Stream) (abstract.Point, []byte) { l := p.c.PointLen() dl := p.PickLen() if dl > len(data) { dl = len(data) } b := make([]byte, l) for { // Pick a random compressed point, and overlay the data. // Decoding will fail if the point is not on the curve. rand.XORKeyStream(b, b) b[0] = (b[0] & 1) | 2 // COMPRESSED, random y bit if data != nil { b[l-1] = byte(dl) // Encode length in low 8 bits copy(b[l-dl-1:l-1], data) // Copy in data to embed } if err := p.UnmarshalBinary(b); err == nil { // See if it decodes! return p, data[dl:] } // otherwise try again... } }
func AESDecrypt(c string, key string) (s string, err error) { var k []byte var block cipher.Block var cfb cipher.Stream var cb []byte var iv []byte k = AESMake256Key(key) cb, err = hex.DecodeString(c) if err != nil { return } block, err = aes.NewCipher(k) if err != nil { return } if len(cb) < aes.BlockSize { err = errors.New("crypt string is too short") return } iv = cb[:aes.BlockSize] cb = cb[aes.BlockSize:] cfb = cipher.NewCFBDecrypter(block, iv) cfb.XORKeyStream(cb, cb) s = bytes.NewBuffer(cb).String() return }
// HideEncode a Int such that it appears indistinguishable // from a HideLen()-byte string chosen uniformly at random, // assuming the Int contains a uniform integer modulo M. // For a Int this always succeeds and returns non-nil. func (i *Int) HideEncode(rand cipher.Stream) []byte { // Lengh of required encoding hidelen := i.HideLen() // Bit-position of the most-significant bit of the modular integer // in the most-significant byte of its encoding. highbit := uint((i.M.BitLen() - 1) & 7) var enc big.Int for { // Pick a random multiplier of a suitable bit-length. var b [1]byte rand.XORKeyStream(b[:], b[:]) mult := int64(b[0] >> highbit) // Multiply, and see if we end up with // a Int of the proper byte-length. // Reroll if we get a result larger than HideLen(), // to ensure uniformity of the resulting encoding. enc.SetInt64(mult).Mul(&i.V, &enc) if enc.BitLen() <= hidelen*8 { break } } b := enc.Bytes() // may be shorter than l if ofs := hidelen - len(b); ofs != 0 { b = append(make([]byte, ofs), b...) } return b }
func AesDecryptData(data, key []byte, ctp string) []byte { block, err := aes.NewCipher(key) if err != nil { return nil } if len(data) < aes.BlockSize { return nil } iv := data[:aes.BlockSize] data_dec := data[aes.BlockSize:] var stream cipher.Stream switch ctp { case "cfb": stream = cipher.NewCFBDecrypter(block, iv) case "ctr": stream = cipher.NewCTR(block, iv) default: stream = cipher.NewOFB(block, iv) } // XORKeyStream can work in-place if the two arguments are the same. stream.XORKeyStream(data_dec, data_dec) return data_dec }
func benchmarkStream(b *testing.B, c cipher.Stream) { b.SetBytes(benchSize) input := make([]byte, benchSize) output := make([]byte, benchSize) for i := 0; i < b.N; i++ { c.XORKeyStream(output, input) } }
// Elligator 1 reverse-map from point to uniform representative. // Returns nil if point has no uniform representative. // See section 3.3 of the Elligator paper. func (el *el1param) HideEncode(P point, rand cipher.Stream) []byte { ec := el.ec x, y := P.getXY() var a, b, etar, etarp1, X, z, u, t, t1 nist.Int // condition 1: a = y+1 is nonzero a.Add(y, &ec.one) if a.V.Sign() == 0 { return nil // y+1 = 0, no representative } // etar = r(y-1)/2(y+1) t1.Add(y, &ec.one).Add(&t1, &t1) // 2(y+1) etar.Sub(y, &ec.one).Mul(&etar, &el.r).Div(&etar, &t1) // condition 2: b = (1 + eta r)^2 - 1 is a square etarp1.Add(&ec.one, &etar) // etarp1 = (1 + eta r) b.Mul(&etarp1, &etarp1).Sub(&b, &ec.one) if math.Jacobi(&b.V, b.M) < 0 { return nil // b not a square, no representative } // condition 3: if etar = -2 then x=2s(c-1)Chi(c)/r if etar.Equal(&el.m2) && !x.Equal(&el.c3x) { return nil } // X = -(1+eta r)+((1+eta r)^2-1)^((q+1)/4) X.Exp(&b, &el.pp1d4).Sub(&X, &etarp1) // z = Chi((c-1)sX(1+X)x(X^2+1/c^2)) z.Mul(&el.cm1s, &X).Mul(&z, t.Add(&ec.one, &X)).Mul(&z, x) z.Mul(&z, t.Mul(&X, &X).Add(&t, &el.invc2)) chi(&z, &z) // u = zX u.Mul(&z, &X) // t = (1-u)/(1+u) t.Div(a.Sub(&ec.one, &u), b.Add(&ec.one, &u)) // Map representative to a byte-string by padding the upper byte. // This assumes that the prime c.P is close enough to a power of 2 // that the adversary will never notice the "missing" values; // this is true for the class of curves Elligator1 was designed for. rep, _ := t.MarshalBinary() padmask := el.padmask() if padmask != 0 { var pad [1]byte rand.XORKeyStream(pad[:], pad[:]) rep[0] |= pad[0] & padmask } return rep }
func encrypt_data(plain, keys []byte) ([]byte, error) { var iv, key []byte var block cipher.Block var stream cipher.Stream iv_offset := TotalIVLen res := make([]byte, len(plain)+iv_offset) iv = res[iv_offset-SalsaIVLen : iv_offset] _, err := rand.Read(iv) if err != nil { return nil, err } // For some reason salsa20 API is different key_array := new([32]byte) copy(key_array[:], keys[cipherKeyLen*2:]) salsa20.XORKeyStream(res[iv_offset:], plain, iv, key_array) iv_offset -= SalsaIVLen iv = res[iv_offset-IVLen : iv_offset] _, err = rand.Read(iv) if err != nil { return nil, err } key = keys[cipherKeyLen : cipherKeyLen*2] block, err = twofish.NewCipher(key) if err != nil { return nil, err } stream = cipher.NewCTR(block, iv) stream.XORKeyStream(res[iv_offset:], res[iv_offset:]) iv_offset -= IVLen iv = res[iv_offset-IVLen : iv_offset] _, err = rand.Read(iv) if err != nil { return nil, err } key = keys[:cipherKeyLen] block, err = aes.NewCipher(key) if err != nil { return nil, err } stream = cipher.NewCTR(block, iv) stream.XORKeyStream(res[iv_offset:], res[iv_offset:]) iv_offset -= IVLen if iv_offset != 0 { panic(fmt.Errorf("something went terribly wrong: iv_offset final value non-zero")) } return res, nil }
func test_correctness2(t *testing.T, ec, dc cipher.Stream, sample2, origin2 []byte) { n := mrand.Int() & 0xff for i := 0; i < n; i++ { ec.XORKeyStream(sample2, sample2) } for i := 0; i < n; i++ { dc.XORKeyStream(sample2, sample2) } // assertion if dumpDiff(origin2, sample2) { t.Fatalf("Incorrect result") } }
func (P *point) Pick(data []byte, rand cipher.Stream) (abstract.Point, []byte) { // How many bytes to embed? dl := P.PickLen() if dl > len(data) { dl = len(data) } for { // Pick a random point, with optional embedded data var b [32]byte rand.XORKeyStream(b[:], b[:]) if data != nil { b[0] = byte(dl) // Encode length in low 8 bits copy(b[1:1+dl], data) // Copy in data to embed } if !P.ge.FromBytes(b[:]) { // Try to decode continue // invalid point, retry } // If we're using the full group, // we just need any point on the curve, so we're done. // if c.full { // return P,data[dl:] // } // We're using the prime-order subgroup, // so we need to make sure the point is in that subgroup. // If we're not trying to embed data, // we can convert our point into one in the subgroup // simply by multiplying it by the cofactor. if data == nil { P.Mul(P, cofactor) // multiply by cofactor if P.Equal(nullPoint) { continue // unlucky; try again } return P, data[dl:] // success } // Since we need the point's y-coordinate to hold our data, // we must simply check if the point is in the subgroup // and retry point generation until it is. var Q point Q.Mul(P, primeOrder) if Q.Equal(nullPoint) { return P, data[dl:] // success } // Keep trying... } }
// Elligator 2 reverse-map from point to uniform representative. // Returns nil if point has no uniform representative. // See section 5.3 of the Elligator paper. func (el *el2param) HideEncode(P point, rand cipher.Stream) []byte { edx, edy := P.getXY() var x, y, r, xpA, t1 nist.Int // convert Edwards to Montgomery coordinates el.ed2mont(&x, &y, edx, edy) // condition 1: x != -A if x.Equal(&el.negA) { return nil // x = -A, no representative } // condition 2: if y=0, then x=0 if y.V.Sign() == 0 && x.V.Sign() != 0 { return nil // y=0 but x!=0, no representative } // condition 3: -ux(x+A) is a square xpA.Add(&x, &el.A) t1.Mul(&el.u, &x).Mul(&t1, &xpA).Neg(&t1) if math.Jacobi(&t1.V, t1.M) < 0 { return nil // not a square, no representative } if y.V.Cmp(&el.pm1d2) <= 0 { // y in image of sqrt function r.Mul(&xpA, &el.u).Div(&x, &r) } else { // y not in image of sqrt function r.Mul(&el.u, &x).Div(&xpA, &r) } r.Neg(&r) el.sqrt(&r, &r) // Sanity check on result if r.V.Cmp(&el.pm1d2) > 0 { panic("el2: r too big") } // Map representative to a byte-string by padding the upper byte. // This assumes that the prime c.P is close enough to a power of 2 // that the adversary will never notice the "missing" values; // this is true for the class of curves Elligator1 was designed for. rep, _ := r.MarshalBinary() padmask := el.padmask() if padmask != 0 { var pad [1]byte rand.XORKeyStream(pad[:], pad[:]) rep[0] |= pad[0] & padmask } return rep }
// Set bignum n to a uniform random BigInt with a given maximum BitLen. // If 'exact' is true, choose a BigInt with _exactly_ that BitLen, not less func (n *bignum) RandBits(bitlen uint, exact bool, rand cipher.Stream) *bignum { b := make([]byte, (bitlen+7)/8) rand.XORKeyStream(b, b) highbits := bitlen & 7 if highbits != 0 { b[0] &= ^(0xff << highbits) } if exact { if highbits != 0 { b[0] |= 1 << (highbits - 1) } else { b[0] |= 0x80 } } n.SetBytes(b) return n }
func HandleStream(t net.Conn, f net.Conn, s cipher.Stream) { in := make([]byte, 1024*4) out := make([]byte, 1024*4) for { n, err := f.Read(in) if n > 0 { s.XORKeyStream(out, in[:n]) _, err2 := t.Write(out[:n]) if err != nil || err2 != nil { return } } else { return } } }
func (this *OnlineUser) PullFromClient() { for { var content string err := websocket.Message.Receive(this.Connection, &content) // If user closes or refreshes the browser, a err will occur if err != nil { return } // Podemos modificar el texto que reciben todos los usuarios // content = "prueba" // Obtenemos hash de 256 con la clave h := sha256.New() h.Reset() h.Write([]byte(clave)) key := h.Sum(nil) // Utilizamos la interfaz cipher para descifrar y cifrar var S cipher.Stream // RC4 proporciona un cipher.Stream directamente al ser cifrado en flujo a, err := rc4.NewCipher(key) check(err) S = a // Desciframos y parseamos de []byte a string cadCifrada := []byte(content) plaintext := make([]byte, len(cadCifrada)) S.XORKeyStream(plaintext, cadCifrada) content = string(plaintext[:]) // Mostramos el mensaje a todos m := Message{ MType: TEXT_MTYPE, TextMessage: TextMessage{ UserInfo: this.UserInfo, Time: humanCreatedAt(), Content: content, }, } this.InRoom.Broadcast <- m } }
// After Layout() has been called to layout the header, // the client may call Payload() any number of times // to reserve regions for encrypted payloads in the message. // Returns the byte offset in the message where the payload was placed. // // Although the client could as well encrypt the data before calling Payload(), // we take a cleartext and a cipher.Stream to "make sure" it gets encrypted. // (Callers who really want to do their own encryption can pass in // a no-op cipher.Stream, but this isn't recommended.) func (w *Writer) Payload(data []byte, encrypt cipher.Stream) int { l := len(data) if l == 0 { panic("zero-length payload not allowed") } // Allocate space for the payload lo := w.layout.alloc(l, "payload") hi := lo + l // Expand the message buffer capacity as needed buf := w.growBuf(lo, hi) // Encrypt and copy in the payload. encrypt.XORKeyStream(buf, data) return lo }
func test_correctness(t *testing.T, ec, dc cipher.Stream, sample2, origin2 []byte) { // n-times encrypt, then decrypt all onetime. randSlice(sample2, ec.XORKeyStream) dc.XORKeyStream(sample2, sample2) // assertion if dumpDiff(origin2, sample2) { t.Fatalf("Incorrect result") } // encrypt all onetime. then n-times decrypt ec.XORKeyStream(sample2, sample2) randSlice(sample2, dc.XORKeyStream) // assertion if dumpDiff(origin2, sample2) { t.Fatalf("Incorrect result") } }
func decrypt_data(dst, data, keys []byte) error { var iv, key []byte var block cipher.Block var stream cipher.Stream var err error buffer := append([]byte{}, data...) iv_offset := IVLen iv = buffer[:iv_offset] key = keys[:cipherKeyLen] block, err = aes.NewCipher(key) if err != nil { return err } stream = cipher.NewCTR(block, iv) stream.XORKeyStream(buffer[iv_offset:], buffer[iv_offset:]) iv_offset += IVLen iv = buffer[iv_offset-IVLen : iv_offset] key = keys[cipherKeyLen : cipherKeyLen*2] block, err = twofish.NewCipher(key) if err != nil { return err } stream = cipher.NewCTR(block, iv) stream.XORKeyStream(buffer[iv_offset:], buffer[iv_offset:]) iv_offset += SalsaIVLen iv = buffer[iv_offset-SalsaIVLen : iv_offset] key_array := new([32]byte) copy(key_array[:], keys[cipherKeyLen*2:]) salsa20.XORKeyStream(dst, buffer[iv_offset:], iv, key_array) if len(buffer[iv_offset:]) != len(data)-TotalIVLen { return fmt.Errorf("something went terribly wrong: bufsz is wrong") } return nil }
func Obfs3fHandshake(wire net.Conn, is_server bool) (io.ReadWriteCloser, error) { var their_public dh_public_key var our_keypair = dh_gen_key(1536) var secret []byte var write_rc4, read_rc4 cipher.Stream their_public = make([]byte, 1536/8) if is_server { _, err := io.ReadFull(wire, their_public) if err != nil { return nil, err } _, err = wire.Write(our_keypair.Public) if err != nil { return nil, err } secret = dh_gen_secret(our_keypair.Private, their_public) write_rc4, _ = rc4.NewCipher(KeyedHash(secret, []byte("obfs3f_downstr"))) read_rc4, _ = rc4.NewCipher(KeyedHash(secret, []byte("obfs3f_upstr"))) } else { _, err := wire.Write(our_keypair.Public) if err != nil { return nil, err } _, err = io.ReadFull(wire, their_public) if err != nil { return nil, err } secret = dh_gen_secret(our_keypair.Private, their_public) write_rc4, _ = rc4.NewCipher(KeyedHash(secret, []byte("obfs3f_upstr"))) read_rc4, _ = rc4.NewCipher(KeyedHash(secret, []byte("obfs3f_downstr"))) } read_rc4.XORKeyStream(make([]byte, 8192), make([]byte, 8192)) write_rc4.XORKeyStream(make([]byte, 8192), make([]byte, 8192)) toret := &Obfs3f{read_rc4, write_rc4, wire} thing := make(chan bool) go func() { randlen := make([]byte, 2) rand.Read(randlen) rlint := int(randlen[0])*256 + int(randlen[1]) xaxa := make([]byte, rlint) toret.Write(randlen) toret.Write(xaxa) thing <- true }() randlen := make([]byte, 2) _, err := io.ReadFull(toret, randlen) if err != nil { return nil, err } _, err = io.ReadFull(toret, make([]byte, int(randlen[0])*256+int(randlen[1]))) if err != nil { return nil, err } <-thing return io.ReadWriteCloser(toret), nil }
func (this *OnlineUser) PushToClient() { for b := range this.Send { // Podemos modificar el texto que se envia // b.TextMessage.Content = "prueba" // Obtenemos hash de 256 con la clave h := sha256.New() h.Reset() h.Write([]byte(clave)) key := h.Sum(nil) // Utilizamos la interfaz cipher para descifrar y cifrar var S cipher.Stream // RC4 proporciona un cipher.Stream directamente al ser cifrado en flujo c, error := rc4.NewCipher(key) check(error) S = c // Ciframos plaintext := []byte(b.TextMessage.Content) cadCifrada := make([]byte, len(plaintext)) S.XORKeyStream(cadCifrada, plaintext) // Enviamos parseando de []byte a string b.TextMessage.Content = string(cadCifrada[:]) // Enviamos la cadena cifrada err := websocket.JSON.Send(this.Connection, b) if err != nil { break } } }
// Choose a uniform random BigInt with a given maximum BitLen. // If 'exact' is true, choose a BigInt with _exactly_ that BitLen, not less func Bits(bitlen uint, exact bool, rand cipher.Stream) []byte { b := make([]byte, (bitlen+7)/8) rand.XORKeyStream(b, b) highbits := bitlen & 7 if highbits != 0 { b[0] &= ^(0xff << highbits) } if exact { if highbits != 0 { b[0] |= 1 << (highbits - 1) } else { b[0] |= 0x80 } } return b }
func encodeAndWrite(conn net.Conn, in []byte, s cipher.Stream) { out := make([]byte, len(in)) s.XORKeyStream(out, in) conn.Write(out) }
func readAndDecode(conn net.Conn, out []byte, s cipher.Stream) { in := make([]byte, len(out)) conn.Read(in) s.XORKeyStream(out, in) }
// Choose a random n-byte slice func Bytes(n int, rand cipher.Stream) []byte { b := make([]byte, n) rand.XORKeyStream(b, b) return b }
// force filling xor buffer func initStream(chacha cipher.Stream) { tmp := make([]byte, _CHACHA_STREAM_SIZE) chacha.XORKeyStream(tmp, tmp) }
// Pick a [pseudo-]random curve point with optional embedded data, // filling in the point's x,y coordinates // and returning any remaining data not embedded. func (c *curve) pickPoint(P point, data []byte, rand cipher.Stream) []byte { // How much data to embed? dl := c.pickLen() if dl > len(data) { dl = len(data) } // Retry until we find a valid point var x, y nist.Int var Q abstract.Point for { // Get random bits the size of a compressed Point encoding, // in which the topmost bit is reserved for the x-coord sign. l := c.PointLen() b := make([]byte, l) rand.XORKeyStream(b, b) // Interpret as little-endian if data != nil { b[0] = byte(dl) // Encode length in low 8 bits copy(b[1:1+dl], data) // Copy in data to embed } util.Reverse(b, b) // Convert to big-endian form xsign := b[0] >> 7 // save x-coordinate sign bit b[0] &^= 0xff << uint(c.P.BitLen()&7) // clear high bits y.M = &c.P // set y-coordinate y.SetBytes(b) if !c.solveForX(&x, &y) { // Corresponding x-coordinate? continue // none, retry } // Pick a random sign for the x-coordinate if c.coordSign(&x) != uint(xsign) { x.Neg(&x) } // Initialize the point P.initXY(&x.V, &y.V, c.self) if c.full { // If we're using the full group, // we just need any point on the curve, so we're done. return data[dl:] } // We're using the prime-order subgroup, // so we need to make sure the point is in that subgroup. // If we're not trying to embed data, // we can convert our point into one in the subgroup // simply by multiplying it by the cofactor. if data == nil { P.Mul(P, &c.cofact) // multiply by cofactor if P.Equal(c.null) { continue // unlucky; try again } return data[dl:] } // Since we need the point's y-coordinate to make sense, // we must simply check if the point is in the subgroup // and retry point generation until it is. if Q == nil { Q = c.self.Point() } Q.Mul(P, &c.order) if Q.Equal(c.null) { return data[dl:] } // Keep trying... } }
// Download file from filesystem func (m Mega) DownloadFile(src *Node, dstpath string, progress *chan int) error { m.FS.mutex.Lock() defer m.FS.mutex.Unlock() defer func() { if progress != nil { close(*progress) } }() if src == nil { return EARGS } var msg [1]DownloadMsg var res [1]DownloadResp var outfile *os.File var mutex sync.Mutex _, err := os.Stat(dstpath) if os.IsExist(err) { os.Remove(dstpath) } outfile, err = os.OpenFile(dstpath, os.O_RDWR|os.O_CREATE, 0600) if err != nil { return err } msg[0].Cmd = "g" msg[0].G = 1 msg[0].N = src.hash request, _ := json.Marshal(msg) result, err := m.api_request(request) if err != nil { return err } err = json.Unmarshal(result, &res) if err != nil { return err } resourceUrl := res[0].G _, err = decryptAttr(src.meta.key, []byte(res[0].Attr)) aes_block, _ := aes.NewCipher(src.meta.key) mac_data := a32_to_bytes([]uint32{0, 0, 0, 0}) mac_enc := cipher.NewCBCEncrypter(aes_block, mac_data) t := bytes_to_a32(src.meta.iv) iv := a32_to_bytes([]uint32{t[0], t[1], t[0], t[1]}) sorted_chunks := []int{} chunks := getChunkSizes(int(res[0].Size)) chunk_macs := make([][]byte, len(chunks)) for k, _ := range chunks { sorted_chunks = append(sorted_chunks, k) } sort.Ints(sorted_chunks) workch := make(chan int) errch := make(chan error, 1) wg := sync.WaitGroup{} // Fire chunk download workers for w := 0; w < m.dl_workers; w++ { wg.Add(1) go func() { defer wg.Done() var id int var ok bool for { // Wait for work blocked on channel select { case err := <-errch: errch <- err return case id, ok = <-workch: if ok == false { return } } var resource *http.Response mutex.Lock() chk_start := sorted_chunks[id] chk_size := chunks[chk_start] mutex.Unlock() chunk_url := fmt.Sprintf("%s/%d-%d", resourceUrl, chk_start, chk_start+chk_size-1) for retry := 0; retry < m.retries+1; retry++ { resource, err = client.Get(chunk_url) if err == nil { break } } var ctr_iv []uint32 var ctr_aes cipher.Stream var chunk []byte if err == nil { ctr_iv = bytes_to_a32(src.meta.iv) ctr_iv[2] = uint32(uint64(chk_start) / 0x1000000000) ctr_iv[3] = uint32(chk_start / 0x10) ctr_aes = cipher.NewCTR(aes_block, a32_to_bytes(ctr_iv)) chunk, err = ioutil.ReadAll(resource.Body) } if err != nil { errch <- err return } resource.Body.Close() ctr_aes.XORKeyStream(chunk, chunk) outfile.WriteAt(chunk, int64(chk_start)) enc := cipher.NewCBCEncrypter(aes_block, iv) i := 0 block := []byte{} chunk = paddnull(chunk, 16) for i = 0; i < len(chunk); i += 16 { block = chunk[i : i+16] enc.CryptBlocks(block, block) } mutex.Lock() if len(chunk_macs) > 0 { chunk_macs[id] = make([]byte, 16) copy(chunk_macs[id], block) } mutex.Unlock() if progress != nil { *progress <- chk_size } } }() } // Place chunk download jobs to chan for id := 0; id < len(chunks); { select { case workch <- id: id++ if id == len(chunks) { close(workch) break } case err := <-errch: errch <- err break } } wg.Wait() select { case err = <-errch: default: } if err != nil { os.Remove(dstpath) return err } for _, v := range chunk_macs { mac_enc.CryptBlocks(mac_data, v) } outfile.Close() tmac := bytes_to_a32(mac_data) if bytes.Equal(a32_to_bytes([]uint32{tmac[0] ^ tmac[1], tmac[2] ^ tmac[3]}), src.meta.mac) == false { return EMACMISMATCH } return nil }