func (kx *KeyExchange) exchange2() ([]byte, error) { reply, err := kx.meetingPlace.Exchange(kx.Log, kx.meeting2[:], kx.message2[:], kx.ShutdownChan) if err != nil { return nil, err } var nonce [24]byte if len(reply) < len(nonce) { return nil, errors.New("panda: meeting point reply too small") } if kx.sharedKey[0] == 0 && kx.sharedKey[1] == 0 { panic("here") } copy(nonce[:], reply) message, ok := secretbox.Open(nil, reply[24:], &nonce, &kx.sharedKey) if !ok { return nil, errors.New("panda: peer's message cannot be authenticated") } if len(message) < 4 { return nil, errors.New("panda: peer's message is invalid") } l := binary.LittleEndian.Uint32(message) message = message[4:] if l > uint32(len(message)) { return nil, errors.New("panda: peer's message is truncated") } message = message[:int(l)] return message, nil }
// OpenWithKey is the same as Open, but a different key can be passed in. func (s *Service) OpenWithKey(e *SealedBytes, secretKey *[SecretKeyLength]byte) (byt []byte, err error) { // once function is complete, check if we are returning err or not. // if we are, return emit a failure metric, if not a success metric. defer func() { if err == nil { s.metricsClient.Inc("success", 1, 1) } else { s.metricsClient.Inc("failure", 1, 1) } }() // check that we either initialized with a key or one was passed in if secretKey == nil { return nil, fmt.Errorf("secret key is nil") } // convert nonce to an array nonce, err := nonceSliceToArray(e.Nonce) if err != nil { return nil, err } // decrypt var decrypted []byte decrypted, ok := secretbox.Open(decrypted, e.Ciphertext, nonce, secretKey) if !ok { return nil, fmt.Errorf("unable to decrypt message") } return decrypted, nil }
func (nd *NaClDecryptor) decrypt(buf []byte) ([]byte, bool) { seqNoAndDF := binary.BigEndian.Uint64(buf[:8]) df := (seqNoAndDF & (1 << 63)) != 0 seqNo := seqNoAndDF & ((1 << 63) - 1) var di *NaClDecryptorInstance if df { di = nd.instanceDF } else { di = nd.instance } binary.BigEndian.PutUint64(di.nonce[16:24], seqNoAndDF) result, success := secretbox.Open(nil, buf[8:], &di.nonce, nd.sessionKey) if !success { return nil, false } // Drop duplicates. We do this *after* decryption since we must // not advance our state unless decryption succeeded. Doing so // would open an easy attack vector where an adversary could // inject a packet with a sequence number of (1 << 63) - 1, // causing all subsequent genuine packets to get dropped. offset, usedOffsets := di.advanceState(seqNo) if usedOffsets == nil || usedOffsets.Contains(offset) { // We have detected a possible replay attack, but it is // possible we may have just received a very old packet, or // duplication may have occurred in the network. So let's just // drop the packet silently. return nil, true } usedOffsets.Add(offset) return result, success }
func (receiver *EncryptedTCPReceiver) Decode(msg []byte) ([]byte, error) { decodedMsg, success := secretbox.Open(nil, msg, &receiver.state.nonce, receiver.state.sessionKey) if !success { return nil, fmt.Errorf("Unable to decrypt TCP msg") } receiver.state.advance() return decodedMsg, nil }
// decrypt extracts the nonce from the ciphertext, and attempts to // decrypt with NaCl's secretbox. func decrypt(key *[keySize]byte, in []byte) ([]byte, bool) { if len(in) < nonceSize { return nil, false } var nonce [nonceSize]byte copy(nonce[:], in) return secretbox.Open(nil, in[nonceSize:], &nonce, key) }
// trySavedKeys tries to decrypt ciphertext using keys saved for missing messages. func (r *Ratchet) trySavedKeys(ciphertext []byte) ([]byte, error) { if len(ciphertext) < sealedHeaderSize { return nil, errors.New("ratchet: header too small to be valid") } sealedHeader := ciphertext[:sealedHeaderSize] var nonce [24]byte copy(nonce[:], sealedHeader) sealedHeader = sealedHeader[len(nonce):] for headerKey, messageKeys := range r.saved { header, ok := secretbox.Open(nil, sealedHeader, &nonce, &headerKey) if !ok { continue } if len(header) != headerSize { continue } msgNum := binary.LittleEndian.Uint32(header[:4]) msgKey, ok := messageKeys[msgNum] if !ok { // This is a fairly common case: the message key might // not have been saved because it's the next message // key. return nil, nil } sealedMessage := ciphertext[sealedHeaderSize:] copy(nonce[:], header[nonceInHeaderOffset:]) msg, ok := secretbox.Open(nil, sealedMessage, &nonce, &msgKey.key) if !ok { return nil, errors.New("ratchet: corrupt message") } delete(messageKeys, msgNum) if len(messageKeys) == 0 { delete(r.saved, headerKey) } return msg, nil } return nil, nil }
func (c *Conn) Read(out []byte) (n int, err error) { if len(c.readPending) > 0 { n = copy(out, c.readPending) c.readPending = c.readPending[n:] return } if c.readBuffer == nil { c.readBuffer = make([]byte, blockSize+2) } if _, err := io.ReadFull(c.conn, c.readBuffer[:2]); err != nil { return 0, err } n = int(c.readBuffer[0]) | int(c.readBuffer[1])<<8 if n > len(c.readBuffer) { return 0, errors.New("transport: peer's message too large for Read") } if _, err := io.ReadFull(c.conn, c.readBuffer[:n]); err != nil { return 0, err } var ok bool if len(out) >= n-secretbox.Overhead { // We can decrypt directly into the output buffer. out, ok = secretbox.Open(out[:0], c.readBuffer[:n], &c.readSequence, &c.readKey) n = len(out) } else { // We need to decrypt into a side buffer and copy a prefix of // the result into the caller's buffer. c.decryptBuffer, ok = secretbox.Open(c.decryptBuffer[:0], c.readBuffer[:n], &c.readSequence, &c.readKey) n = copy(out, c.decryptBuffer) c.readPending = c.decryptBuffer[n:] } incSequence(&c.readSequence) if !ok { c.readPending = c.readPending[:0] return 0, errors.New("transport: bad MAC") } return }
func (c *Conn) decrypt(data []byte) ([]byte, error) { if !c.readKeyValid { return data, nil } decrypted, ok := secretbox.Open(nil, data, &c.readSequence, &c.readKey) incSequence(&c.readSequence) if !ok { return nil, errors.New("transport: bad MAC") } return decrypted, nil }
func decrypt(key, ciphertext []byte) ([]byte, error) { if len(ciphertext) < nonceLen+secretbox.Overhead { return nil, fmt.Errorf("message too short") } var nonce [nonceLen]byte copy(nonce[:], ciphertext) ciphertext = ciphertext[nonceLen:] text, ok := secretbox.Open(nil, ciphertext, &nonce, makeKey(key)) if !ok { return nil, fmt.Errorf("decryption failure") } return text, nil }
// Decrypt decrypts a message using XSalsa20-Poly1305 and outputs it to dst. // Returns false if decryption failed (authentication tag mismatch). func (sb *secretBoxMode) Decrypt(dst []byte, src []byte, nonce []byte) bool { if len(src) <= sb.Overhead() { panic("cryptstate: bad src") } if len(nonce) != 24 { panic("cryptstate: bad nonce length") } noncePtr := (*[24]byte)(unsafe.Pointer(&nonce[0])) _, ok := secretbox.Open(dst[0:0], src, noncePtr, &sb.key) return ok }
func DecryptPrefixNonce(ciphertxt []byte, secret *[32]byte) ([]byte, bool) { if len(ciphertxt) < secretbox.Overhead+24 { return nil, false } // There is no way to nicely convert from a slice to an // array. So have to used the following loop. var nonce [24]byte for idx, e := range ciphertxt[0:24] { nonce[idx] = e } ciphertxt = ciphertxt[24:] return secretbox.Open(nil, ciphertxt, &nonce, secret) }
// TODO : consider caching the last deciphered chunk func (this *CipherReaderAt) ReadAt(p []byte, off int64) (n int, err error) { log.Printf("ReadAt len(p):%v, off:%v\n", len(p), off) // read Nonce if not yet read if this.Nonce == nil { this.Nonce = &[24]byte{} _, err := this.Reader.ReadAt(this.Nonce[:], 0) if err != nil { return 0, err } } // ... for len(p) > 0 { chunkIndex := off / (this.ChunkSize - secretbox.Overhead) chunkStart := chunkIndex * this.ChunkSize offChunk := off - chunkIndex*(this.ChunkSize-secretbox.Overhead) log.Printf(" - chunkIndex: %v, chunkStart: %v, offChunk: %v\n", chunkIndex, chunkStart, offChunk) // compute nonce, basically a base 256 addition operation var nonce [24]byte copy(nonce[:], this.Nonce[:]) { ci := chunkIndex // copy i := 0 carry := int16(0) for ci > 0 || carry > 0 { sum := int16(ci % 256) sum += int16(nonce[i]) sum += int16(carry) nonce[i] = byte(sum % 256) carry = int16(sum >> 8) ci >>= 8 i++ } log.Printf(" - nonce: %v", nonce) } numRead, err := this.Reader.ReadAt(this.Chunk, 24+chunkStart) if err != nil && err != io.EOF { return n, err } openedChunk, ok := secretbox.Open(nil, this.Chunk[:numRead], &nonce, this.Key) //fmt.Println(colors.Cyan("nonce:", nonce, " key:", this.Key, " numRead:", numRead)) if !ok { return n, errors.New(fmt.Sprintf("Failed to decipher chunk %v", chunkIndex)) } copied := copy(p, openedChunk[offChunk:]) p = p[copied:] n += copied off += int64(copied) } return n, nil }
func (s *Convergent) Get(key []byte) ([]byte, error) { boxedkey := s.computeBoxedKey(key) box, err := s.untrusted.Get(boxedkey) if err != nil { return nil, err } nonce := s.makeNonce(key) plain, ok := secretbox.Open(nil, box, nonce, s.secret) if !ok { return nil, Corrupt{Key: key} } return plain, nil }
// decrypt extracts the nonce from the ciphertext, and attempts to // decrypt with NaCl's secretbox. func decrypt(key *[keySize]byte, message []byte) ([]byte, error) { if len(message) < (nonceSize + secretbox.Overhead) { return nil, ErrDecrypt } var nonce [nonceSize]byte copy(nonce[:], message[:nonceSize]) out, ok := secretbox.Open(nil, message[nonceSize:], &nonce, key) if !ok { return nil, ErrDecrypt } return out, nil }
func unbox(key *[32]byte, body []byte) ([]byte, error) { var nonce [24]byte if len(body) < len(nonce)+secretbox.Overhead+2 { return nil, errors.New("panda: reply from server is too short to be valid") } copy(nonce[:], body) unsealed, ok := secretbox.Open(nil, body[len(nonce):], &nonce, key) if !ok { return nil, errors.New("panda: failed to authenticate reply from server") } l := int(unsealed[0]) | int(unsealed[1])<<8 unsealed = unsealed[2:] if l > len(unsealed) { return nil, errors.New("panda: corrupt but authentic message found") } return unsealed[:l], nil }
// importTombFile decrypts a file with the given path, using a hex-encoded key // and loads the client state from the result. func (c *client) importTombFile(stateFile *disk.StateFile, keyHex, path string) error { keyBytes, err := hex.DecodeString(keyHex) if err != nil { return err } var key [32]byte var nonce [24]byte if len(keyBytes) != len(key) { return fmt.Errorf("Incorrect key length: %d (want %d)", len(keyBytes), len(key)) } copy(key[:], keyBytes) tombBytes, err := ioutil.ReadFile(path) if err != nil { return err } plaintext, ok := secretbox.Open(nil, tombBytes, &nonce, &key) if !ok { return errors.New("Incorrect key") } c.stateLock, err = stateFile.Lock(true /* create */) if c.stateLock == nil && err == nil { return errors.New("Output statefile is locked.") } if err != nil { return err } writerChan := make(chan disk.NewState) writerDone := make(chan struct{}) go stateFile.StartWriter(writerChan, writerDone) writerChan <- disk.NewState{State: plaintext} close(writerChan) <-writerDone return nil }
func (m *secretboxMode) Decrypt(encrypted []byte) ([]byte, bool) { var opened []byte var nonce [24]byte if len(encrypted) < 24 { log.Printf("secretbox: Not good: len (%d) < 24\n", len(encrypted)) return nil, false } for i := 0; i < 24; i++ { nonce[i] = encrypted[len(encrypted)-24+i] } data := encrypted[:len(encrypted)-24] opened, ok := secretbox.Open(opened[:0], data, &nonce, &m.key) if !ok { log.Printf("secretbox: Not good: Open() returned false\n") } return opened, ok }
func (c *client) loadState(b []byte, key *[32]byte) error { if len(b) < sCryptSaltLen+24*smearedCopies { return errors.New("state file is too small to be valid") } b = b[sCryptSaltLen:] var nonce [24]byte for i := 0; i < smearedCopies; i++ { for j := 0; j < 24; j++ { nonce[j] ^= b[24*i+j] } } b = b[24*smearedCopies:] plaintext, ok := secretbox.Open(nil, b, &nonce, key) if !ok { return badPasswordError } if len(plaintext) < 4 { return errors.New("state file corrupt") } length := binary.LittleEndian.Uint32(plaintext[:4]) plaintext = plaintext[4:] if length > 1<<31 || length > uint32(len(plaintext)) { return errors.New("state file corrupt") } plaintext = plaintext[:int(length)] var state protos.State if err := proto.Unmarshal(plaintext, &state); err != nil { return err } if err := c.unmarshal(&state); err != nil { return err } return nil }
func loadOldState(b []byte, key *[32]byte) (*State, error) { const ( SCryptSaltLen = 32 smearedCopies = 32768 / 24 ) if len(b) < SCryptSaltLen+24*smearedCopies { return nil, errors.New("state file is too small to be valid") } var nonce [24]byte for i := 0; i < smearedCopies; i++ { for j := 0; j < 24; j++ { nonce[j] ^= b[24*i+j] } } b = b[24*smearedCopies:] plaintext, ok := secretbox.Open(nil, b, &nonce, key) if !ok { return nil, BadPasswordError } if len(plaintext) < 4 { return nil, errors.New("state file corrupt") } length := binary.LittleEndian.Uint32(plaintext[:4]) plaintext = plaintext[4:] if length > 1<<31 || length > uint32(len(plaintext)) { return nil, errors.New("state file corrupt") } plaintext = plaintext[:int(length)] var state State if err := proto.Unmarshal(plaintext, &state); err != nil { return nil, err } return &state, nil }
func (s *httpService) getBackendSticky(req *http.Request) (*httputil.ClientConn, *http.Cookie) { cookie, err := req.Cookie(stickyCookie) if err != nil { return s.getNewBackendSticky() } data, err := base64.StdEncoding.DecodeString(cookie.Value) if err != nil { return s.getNewBackendSticky() } var nonce [24]byte if len(data) < len(nonce) { return s.getNewBackendSticky() } copy(nonce[:], data) res, ok := secretbox.Open(nil, data[len(nonce):], &nonce, s.cookieKey) if !ok { return s.getNewBackendSticky() } addr := string(res) ok = false for _, a := range s.ss.Addrs() { if a == addr { ok = true break } } if !ok { return s.getNewBackendSticky() } backend, err := net.Dial("tcp", string(addr)) if err != nil { return s.getNewBackendSticky() } return httputil.NewClientConn(backend, nil), nil }
func main() { runtime.GOMAXPROCS(2) flag.Parse() if len(*secret) == 0 { fmt.Fprintf(os.Stderr, "The shared secret must be given as --secret\n") os.Exit(2) } if len(*keyFile) == 0 { fmt.Fprintf(os.Stderr, "The path to a find containing the public key material to exchange must be given as --key-file\n") os.Exit(2) } pubKeyBytes, err := ioutil.ReadFile(*keyFile) if err != nil { fmt.Fprintf(os.Stderr, "Failed to read key file: %s\n", err) os.Exit(2) } const maxBody = 4096 if limit := maxBody - 24 - secretbox.Overhead; len(pubKeyBytes) > limit { fmt.Fprintf(os.Stderr, "--key-file is too large (%d bytes of a maximum of %d)\n", len(pubKeyBytes), limit) os.Exit(2) } // Run scrypt on a goroutine so that we can overlap it with the network // delay. keyChan := make(chan []byte) go deriveKey(keyChan, *secret) var dialer proxy.Dialer dialer = proxy.Direct if len(*torProxy) > 0 { fmt.Fprintf(os.Stderr, "Using SOCKS5 proxy at %s\n", *torProxy) dialer, err = proxy.SOCKS5("tcp", *torProxy, nil, dialer) if err != nil { panic(err) } } fmt.Fprintf(os.Stderr, "Starting TCP connection to %s\n", *server) rawConn, err := dialer.Dial("tcp", *server) if err != nil { fmt.Fprintf(os.Stderr, "Failed to connect to server: %s\n", err) os.Exit(2) } var conn net.Conn if *useTLS { hostname, _, err := net.SplitHostPort(*server) if err != nil { fmt.Fprintf(os.Stderr, "Failed to split %s into host and post: %s\n", *server, err) os.Exit(2) } tlsConn := tls.Client(rawConn, &tls.Config{ ServerName: hostname, }) fmt.Fprintf(os.Stderr, "Starting TLS handshake\n") if err := tlsConn.Handshake(); err != nil { rawConn.Close() fmt.Fprintf(os.Stderr, "TLS handshake failed: %s\n", err) os.Exit(2) } conn = tlsConn } else { conn = rawConn } defer conn.Close() var keySlice []byte select { case keySlice = <-keyChan: default: fmt.Fprintf(os.Stderr, "Waiting for key derivation to complete. This may take some time.\n") keySlice = <-keyChan } var key [32]byte copy(key[:], keySlice) mac := hmac.New(sha256.New, key[:]) mac.Write(pubKeyBytes) nonceSlice := mac.Sum(nil) var nonce [24]byte copy(nonce[:], nonceSlice) box := make([]byte, len(nonce)+secretbox.Overhead+len(pubKeyBytes)) copy(box, nonce[:]) secretbox.Seal(box[len(nonce):len(nonce)], pubKeyBytes, &nonce, &key) h := sha256.New() h.Write(key[:]) tag := h.Sum(nil) body := bytes.NewReader(box) request, err := http.NewRequest("POST", "http://"+*server+"/exchange/"+hex.EncodeToString(tag), body) if err != nil { panic(err) } request.ContentLength = int64(len(box)) request.Header.Add("Content-Type", "application/octet-stream") request.Write(conn) fmt.Fprintf(os.Stderr, "Request sent. Waiting for HTTP reply\n") replyReader := bufio.NewReader(conn) response, err := http.ReadResponse(replyReader, request) if err != nil { fmt.Fprintf(os.Stderr, "Error reading reply from server: %s\n", err) os.Exit(2) } switch response.StatusCode { case 409: fmt.Fprintf(os.Stderr, "The transaction failed because this key has been used recently by two other parties.\n") os.Exit(2) case 204: fmt.Fprintf(os.Stderr, "Material submitted, but the other party has yet to start the process. Try again later with the same arguments.\n") os.Exit(1) case 200: r := &io.LimitedReader{R: response.Body, N: maxBody + 1} body, err := ioutil.ReadAll(r) if err != nil { fmt.Fprintf(os.Stderr, "Error reading from server: %s\n", err) os.Exit(2) } if len(body) > maxBody { fmt.Fprintf(os.Stderr, "Reply from server is too large\n") os.Exit(2) } if len(body) < len(nonce)+secretbox.Overhead { fmt.Fprintf(os.Stderr, "Reply from server is too short to be valid: %x\n", body) os.Exit(2) } copy(nonce[:], body) unsealed, ok := secretbox.Open(nil, body[len(nonce):], &nonce, &key) if !ok { fmt.Fprintf(os.Stderr, "Failed to authenticate reply from server\n") os.Exit(2) } os.Stdout.Write(unsealed) default: fmt.Fprintf(os.Stderr, "HTTP error from server: %s\n", response.Status) io.Copy(os.Stderr, response.Body) os.Exit(2) } }
func saveDecrypted(c chan interface{}, outPath string, id uint64, in *os.File, detachment *pond.Message_Detachment, killChan chan bool) error { out, err := os.OpenFile(outPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { return errors.New("failed to open output: " + err.Error()) } defer out.Close() var key [32]byte var nonce [24]byte blockSize := *detachment.ChunkSize + secretbox.Overhead if blockSize > 1<<20 { return errors.New("chunk size too large") } copy(key[:], detachment.Key) var bytesIn, bytesOut uint64 buf := make([]byte, blockSize) var decrypted []byte var lastUpdate time.Time BlockLoop: for { n, err := io.ReadFull(in, buf) switch err { case nil: break case io.ErrUnexpectedEOF, io.EOF: break BlockLoop default: return errors.New("failed to read from source: " + err.Error()) } bytesIn += uint64(n) var ok bool decrypted, ok = secretbox.Open(decrypted[:0], buf, &nonce, &key) if !ok { os.Remove(outPath) return errors.New("input corrupt") } if bytesOut != *detachment.Size { if n := bytesOut + uint64(len(decrypted)); n > *detachment.Size { decrypted = decrypted[:*detachment.Size-bytesOut] } bytesOut += uint64(len(decrypted)) if _, err := out.Write(decrypted); err != nil { return errors.New("failed to write to destination: " + err.Error()) } } if bytesIn > *detachment.PaddedSize { // This means that we downloaded more bytes than we // expected. break } incNonce(&nonce) now := time.Now() if lastUpdate.IsZero() || now.Sub(lastUpdate) > 500*time.Millisecond { lastUpdate = now select { case c <- DetachmentProgress{ id: id, done: bytesIn, total: *detachment.PaddedSize, }: break default: } } select { case <-killChan: os.Remove(outPath) return backgroundCanceledError default: break } } if bytesIn != *detachment.PaddedSize { return errors.New("input truncated") } return nil }
// If valid == true, pb[176:] is replaced by the plaintext contents of // the Initiate C'->S' box. func (s *server) checkInitiate(pb []byte) (serverShortTermKey []byte, domain string, valid bool) { valid = false if len(pb) < 544 || !bytes.Equal(pb[:8], initiateMagic) { return } // Try to open the cookie. var nonce [24]byte copy(nonce[:], minuteNoncePrefix) copy(nonce[len(minuteNoncePrefix):], pb[72:72+16]) var cookie [64]byte if _, ok := secretbox.Open(cookie[:0], pb[88:168], &nonce, &s.minuteKey); !ok { if _, ok = secretbox.Open(cookie[:0], pb[88:168], &nonce, &s.prevMinuteKey); !ok { return } } // Check that the cookie and client match if !bytes.Equal(cookie[:32], pb[40:40+32]) { return } // Extract server short-term secret key var serverKey [32]byte serverShortTermKey = serverKey[:] copy(serverShortTermKey, cookie[32:]) // Open the Initiate box using both short-term secret keys. copy(nonce[:], initiateNoncePrefix) copy(nonce[len(initiateNoncePrefix):], pb[168:168+8]) var clientShortTermKey [32]byte copy(clientShortTermKey[:], pb[40:40+32]) initiate := make([]byte, len(pb[176:])-box.Overhead) if _, ok := box.Open(initiate[:0], pb[176:], &nonce, &clientShortTermKey, &serverKey); !ok { return } if domain = domainToString(initiate[96 : 96+256]); domain == "" { return } // Extract client long-term public key and check the vouch // subpacket. var clientLongTermKey [32]byte copy(clientLongTermKey[:], initiate[:32]) copy(nonce[:], vouchNoncePrefix) copy(nonce[len(vouchNoncePrefix):], initiate[32:32+16]) var vouch [32]byte if _, ok := box.Open(vouch[:0], initiate[48:48+48], &nonce, &clientLongTermKey, &s.longTermSecretKey); !ok { return } if !bytes.Equal(vouch[:], pb[40:40+32]) { return } // The Initiate packet is valid, replace the encrypted box with // the plaintext and return. copy(pb[176:], initiate) for i := len(pb) - box.Overhead; i < len(pb); i++ { pb[i] = 0 } valid = true return }
func (r *Ratchet) Decrypt(ciphertext []byte) ([]byte, error) { msg, err := r.trySavedKeys(ciphertext) if err != nil || msg != nil { return msg, err } sealedHeader := ciphertext[:sealedHeaderSize] sealedMessage := ciphertext[sealedHeaderSize:] var nonce [24]byte copy(nonce[:], sealedHeader) sealedHeader = sealedHeader[len(nonce):] header, ok := secretbox.Open(nil, sealedHeader, &nonce, &r.recvHeaderKey) ok = ok && !isZeroKey(&r.recvHeaderKey) if ok { if len(header) != headerSize { return nil, errors.New("ratchet: incorrect header size") } messageNum := binary.LittleEndian.Uint32(header[:4]) provisionalChainKey, messageKey, savedKeys, err := r.saveKeys(&r.recvHeaderKey, &r.recvChainKey, messageNum, r.recvCount) if err != nil { return nil, err } copy(nonce[:], header[nonceInHeaderOffset:]) msg, ok := secretbox.Open(nil, sealedMessage, &nonce, &messageKey) if !ok { return nil, errors.New("ratchet: corrupt message") } copy(r.recvChainKey[:], provisionalChainKey[:]) r.mergeSavedKeys(savedKeys) r.recvCount = messageNum + 1 return msg, nil } header, ok = secretbox.Open(nil, sealedHeader, &nonce, &r.nextRecvHeaderKey) if !ok { return nil, errors.New("ratchet: cannot decrypt") } if len(header) != headerSize { return nil, errors.New("ratchet: incorrect header size") } if r.ratchet { return nil, errors.New("ratchet: received message encrypted to next header key without ratchet flag set") } messageNum := binary.LittleEndian.Uint32(header[:4]) prevMessageCount := binary.LittleEndian.Uint32(header[4:8]) _, _, oldSavedKeys, err := r.saveKeys(&r.recvHeaderKey, &r.recvChainKey, prevMessageCount, r.recvCount) if err != nil { return nil, err } var dhPublic, sharedKey, rootKey, chainKey, keyMaterial [32]byte copy(dhPublic[:], header[8:]) curve25519.ScalarMult(&sharedKey, &r.sendRatchetPrivate, &dhPublic) sha := sha256.New() sha.Write(rootKeyUpdateLabel) sha.Write(r.rootKey[:]) sha.Write(sharedKey[:]) var rootKeyHMAC hash.Hash if r.v2 { sha.Sum(keyMaterial[:0]) rootKeyHMAC = hmac.New(sha256.New, keyMaterial[:]) deriveKey(&rootKey, rootKeyLabel, rootKeyHMAC) } else { sha.Sum(rootKey[:0]) rootKeyHMAC = hmac.New(sha256.New, rootKey[:]) } deriveKey(&chainKey, chainKeyLabel, rootKeyHMAC) provisionalChainKey, messageKey, savedKeys, err := r.saveKeys(&r.nextRecvHeaderKey, &chainKey, messageNum, 0) if err != nil { return nil, err } copy(nonce[:], header[nonceInHeaderOffset:]) msg, ok = secretbox.Open(nil, sealedMessage, &nonce, &messageKey) if !ok { return nil, errors.New("ratchet: corrupt message") } copy(r.rootKey[:], rootKey[:]) copy(r.recvChainKey[:], provisionalChainKey[:]) copy(r.recvHeaderKey[:], r.nextRecvHeaderKey[:]) deriveKey(&r.nextRecvHeaderKey, sendHeaderKeyLabel, rootKeyHMAC) for i := range r.sendRatchetPrivate { r.sendRatchetPrivate[i] = 0 } copy(r.recvRatchetPublic[:], dhPublic[:]) r.recvCount = messageNum + 1 r.mergeSavedKeys(oldSavedKeys) r.mergeSavedKeys(savedKeys) r.ratchet = true return msg, nil }
func (sf *StateFile) Read(pw string) (*State, error) { b, err := ioutil.ReadFile(sf.Path) if err != nil { return nil, err } if len(b) < len(headerMagic)+4 { return nil, errors.New("state file is too small to be valid") } if !bytes.Equal(b[:len(headerMagic)], headerMagic[:]) { sf.header.NoErasureStorage = proto.Bool(true) if len(pw) > 0 { sf.header.Scrypt = new(Header_SCrypt) sf.header.KdfSalt = b[:32] if err := sf.deriveKey(pw); err != nil { return nil, err } } b = b[32:] state, err := sf.readOldStyle(b) if err != nil { return nil, err } return state, nil } b = b[len(headerMagic):] headerLen := binary.LittleEndian.Uint32(b) b = b[4:] if headerLen > 1<<16 { return nil, errors.New("state file corrupt") } if len(b) < int(headerLen) { return nil, errors.New("state file truncated") } headerBytes := b[:int(headerLen)] b = b[int(headerLen):] if err := proto.Unmarshal(headerBytes, &sf.header); err != nil { return nil, err } if len(pw) > 0 { if err := sf.deriveKey(pw); err != nil { return nil, err } } if !sf.header.GetNoErasureStorage() { for _, erasureMethod := range erasureRegistry { sf.Erasure = erasureMethod(&sf.header) if sf.Erasure != nil { break } } if sf.Erasure == nil { return nil, errors.New("unknown erasure storage method") } mask, err := sf.Erasure.Read(&sf.key) if err != nil { return nil, err } copy(sf.mask[:], mask[:]) } smearedCopies := int(sf.header.GetNonceSmearCopies()) if len(b) < 24*smearedCopies { return nil, errors.New("state file truncated") } var nonce [24]byte for i := 0; i < smearedCopies; i++ { for j := 0; j < 24; j++ { nonce[j] ^= b[24*i+j] } } b = b[24*smearedCopies:] var effectiveKey [kdfKeyLen]byte for i := range effectiveKey { effectiveKey[i] = sf.mask[i] ^ sf.key[i] } plaintext, ok := secretbox.Open(nil, b, &nonce, &effectiveKey) if !ok { return nil, BadPasswordError } if len(plaintext) < 4 { return nil, errors.New("state file corrupt") } length := binary.LittleEndian.Uint32(plaintext[:4]) plaintext = plaintext[4:] if length > 1<<31 || length > uint32(len(plaintext)) { return nil, errors.New("state file corrupt") } plaintext = plaintext[:int(length)] var state State if err := proto.Unmarshal(plaintext, &state); err != nil { return nil, err } return &state, nil }
// Open authenticates and decrypts a box produced by Seal and appends the // message to out, which must not overlap box. The output will be Overhead // bytes smaller than box. func Open(out, box []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) ([]byte, bool) { var sharedKey [32]byte Precompute(&sharedKey, peersPublicKey, privateKey) return secretbox.Open(out, box, nonce, &sharedKey) }
func (nd *NaClDecryptor) decrypt(buf []byte) ([]byte, error) { offset := binary.BigEndian.Uint16(buf[:2]) df := (offset & (1 << 15)) != 0 offsetNoFlags := offset & ((1 << 15) - 1) var decState *NaClDecryptorInstance if df { decState = nd.instanceDF } else { decState = nd.instance } var nonce *[24]byte var usedOffsets *bit.Set var ok bool if decState.nonce == nil { if offsetNoFlags > (1 << 13) { // offset is already beyond the first quarter and it's the // first thing we've seen?! I don't think so. return nil, fmt.Errorf("Unexpected offset when decrypting UDP packet") } decState.nonce, ok = <-decState.nonceChan if !ok { return nil, fmt.Errorf("Nonce chan closed") } nonce = decState.nonce usedOffsets = decState.usedOffsets decState.highestOffsetSeen = offsetNoFlags } else { highestOffsetSeen := decState.highestOffsetSeen if offsetNoFlags < (1<<13) && highestOffsetSeen > ((1<<14)+(1<<13)) && (highestOffsetSeen-offsetNoFlags) > ((1<<14)+(1<<13)) { // offset is in the first quarter, highestOffsetSeen is in // the top quarter and under a quarter behind us. We // interpret this as we need to move to the next nonce decState.previousUsedOffsets = decState.usedOffsets decState.usedOffsets = bit.New() decState.previousNonce = decState.nonce decState.nonce, ok = <-decState.nonceChan if !ok { return nil, fmt.Errorf("Nonce chan closed") } decState.highestOffsetSeen = offsetNoFlags nonce = decState.nonce usedOffsets = decState.usedOffsets } else if offsetNoFlags > highestOffsetSeen && (offsetNoFlags-highestOffsetSeen) < (1<<13) { // offset is under a quarter above highestOffsetSeen. This // is ok - maybe some packet loss decState.highestOffsetSeen = offsetNoFlags nonce = decState.nonce usedOffsets = decState.usedOffsets } else if offsetNoFlags <= highestOffsetSeen && (highestOffsetSeen-offsetNoFlags) < (1<<13) { // offset is within a quarter of the highest we've // seen. This is ok - just assuming some out-of-order // delivery. nonce = decState.nonce usedOffsets = decState.usedOffsets } else if highestOffsetSeen < (1<<13) && offsetNoFlags > ((1<<14)+(1<<13)) && (offsetNoFlags-highestOffsetSeen) > ((1<<14)+(1<<13)) { // offset is in the last quarter, highestOffsetSeen is in // the first quarter, and offset is under a quarter behind // us. This is ok - as above, just some out of order. But // here it means we're dealing with the previous nonce nonce = decState.previousNonce usedOffsets = decState.previousUsedOffsets } else { return nil, fmt.Errorf("Unexpected offset when decrypting UDP packet") } } offsetNoFlagsInt := int(offsetNoFlags) if usedOffsets.Contains(offsetNoFlagsInt) { return nil, fmt.Errorf("Suspected replay attack detected when decrypting UDP packet") } SetNonceLow15Bits(nonce, offsetNoFlags) result, success := secretbox.Open(nil, buf[2:], nonce, nd.conn.SessionKey) if success { usedOffsets.Add(offsetNoFlagsInt) return result, nil } else { return nil, fmt.Errorf("Unable to decrypt msg via UDP: %v", buf) } }
// OpenAfterPrecomputation performs the same actions as Open, but takes a // shared key as generated by Precompute. func OpenAfterPrecomputation(out, box []byte, nonce *[24]byte, sharedKey *[32]byte) ([]byte, bool) { return secretbox.Open(out, box, nonce, sharedKey) }
func do(keyFile string) error { contents, err := ioutil.ReadFile(os.Args[1]) if err != nil { return err } var detachment pond.Message_Detachment if err := proto.Unmarshal(contents, &detachment); err != nil { return err } size := detachment.GetSize() paddedSize := detachment.GetPaddedSize() chunkSize := uint64(detachment.GetChunkSize()) blockSize := chunkSize + secretbox.Overhead if blockSize > 1<<20 { return errors.New("chunk size too large") } if paddedSize%blockSize != 0 { return errors.New("padded size is not a multiple of the chunk size") } fmt.Fprintf(os.Stderr, `Pond decryption: Original filename: %s Size: %d Padded size: %d Chunk size: %d `, sanitiseForTerminal(detachment.GetFilename()), size, paddedSize, chunkSize) var key [32]byte var nonce [24]byte copy(key[:], detachment.Key) var read, written uint64 buf := make([]byte, blockSize) var decrypted []byte for read < paddedSize { if _, err := io.ReadFull(os.Stdin, buf); err != nil { return err } read += uint64(len(buf)) var ok bool decrypted, ok := secretbox.Open(decrypted[:0], buf, &nonce, &key) if !ok { return errors.New("decryption error") } incNonce(&nonce) todo := size - written if n := uint64(len(decrypted)); todo > n { todo = n } if _, err := os.Stdout.Write(decrypted[:todo]); err != nil { return err } written += todo } return nil }