# Path: src/petmail/errors.py
# class ReplayError(Exception):
#     pass
# 
# class WrongVerfkeyError(Exception):
#     pass
# 
# class UnknownChannelError(Exception):
#     """Message not decryptable by any of our channels."""
# 
# Path: src/petmail/util.py
# def split_into(s, piece_sizes, plus_trailer=False):
#     assert type(s) == type(b"")
#     pieces = []
#     piece_start = 0
#     for size in piece_sizes:
#         piece_end = piece_start+size
#         pieces.append(s[piece_start:piece_end])
#         piece_start = piece_end
#     if plus_trailer:
#         pieces.append(s[piece_start:])
#     else:
#         if piece_start != len(s):
#             raise ValueError("split did not consume entire string")
#     return pieces
# 
# def verify_with_prefix(vk, sm, prefix):
#     m = vk.verify(sm)
#     if not m.startswith(prefix):
#         raise BadSignatureError("missing expected prefix")
#     return m[len(prefix):]
# 
# Path: src/petmail/hkdf.py
# def HKDF(IKM, dkLen, salt=None, info=b"", digest=sha256,
#          _test_expected_PRK=None):
#     assert isinstance(IKM, bytes)
#     assert isinstance(salt, (bytes,type(None)))
#     assert isinstance(info, bytes)
#     hlen = len(digest(b"").digest())
#     assert dkLen <= hlen*255
#     if salt is None:
#         salt = b"\x00"*hlen
#     # extract
#     PRK = hmac.new(salt, IKM, digest).digest()
#     if _test_expected_PRK and _test_expected_PRK != PRK:
#         raise ValueError("test failed")
#     # expand
#     blocks = []
#     counter = 1
#     t = b""
#     while hlen*len(blocks) < dkLen:
#         t = hmac.new(PRK, t+info+chr(counter), digest).digest()
#         blocks.append(t)
#         counter += 1
#     return b"".join(blocks)[:dkLen]
# 
# Path: src/petmail/netstring.py
# def netstring(msg):
#     assert isinstance(msg, str)
#     return "%d:%s," % (len(msg), msg)
# 
# def split_netstrings_and_trailer(s):
#     p = _NetstringParser()
#     p.messages = messages = []
#     p.makeConnection(_EmptyTransport())
#     p.dataReceived(s)
#     return (messages, p._remainingData)
# 
# Path: src/petmail/mailbox/delivery.py
# class OutboundHTTPTransport:
#     """I call mailbox.transport to create msgA, then perform an HTTP POST to a
#     mailbox server."""
#     def __init__(self, db, trecord):
#         self.db = db
#         self.trecord = trecord
# 
#     def send(self, msgC):
#         msgA = createMsgA(self.trecord, msgC)
#         url = str(self.trecord["url"])
#         return client.getPage(url, method="POST", postdata=msgA)
# 
# class ReturnTransport: # for tests
#     """I call mailbox.transport to create msgA, then return it."""
#     def __init__(self, db, trecord):
#         self.db = db
#         self.trecord = trecord
# 
#     def send(self, msgC):
#         msgA = createMsgA(self.trecord, msgC)
#         return defer.succeed(msgA)


import struct, json, os
from hashlib import sha256
from twisted.internet import defer
from ..errors import ReplayError, WrongVerfkeyError, UnknownChannelError
from ..util import split_into, verify_with_prefix
from ..hkdf import HKDF
from ..netstring import netstring, split_netstrings_and_trailer
from .delivery import OutboundHTTPTransport, ReturnTransport
from nacl.public import PrivateKey, PublicKey, Box
from nacl.signing import SigningKey, VerifyKey
from nacl.secret import SecretBox
from nacl.exceptions import CryptoError
        self.db.update("UPDATE addressbook SET next_outbound_seqnum=?"
                       " WHERE id=?",
                       (next_outbound_seqnum+1, self.cid),
                       "addressbook", self.cid)
        self.db.commit()
        seqnum_s = struct.pack(">Q", next_outbound_seqnum)
        my_signkey = SigningKey(res["my_signkey"].decode("hex"))
        privkey2 = PrivateKey.generate()
        pubkey2 = privkey2.public_key.encode()
        assert len(pubkey2) == 32
        crec = json.loads(res["their_channel_record_json"])
        channel_pubkey = crec["channel_pubkey"].decode("hex")
        channel_box = Box(privkey2, PublicKey(channel_pubkey))
        CIDKey = crec["CID_key"].decode("hex")

        authenticator = b"ce0:"+pubkey2
        msgE = "".join([seqnum_s,
                        netstring(my_signkey.sign(authenticator)),
                        json.dumps(payload).encode("utf-8"),
                        ])
        msgD = pubkey2 + channel_box.encrypt(msgE, os.urandom(Box.NONCE_SIZE))

        HmsgD = sha256(msgD).digest()
        CIDToken = build_CIDToken(CIDKey, next_outbound_seqnum)
        sb = SecretBox(CIDKey)
        CIDBox = sb.encrypt(seqnum_s+HmsgD+channel_pubkey,
                            os.urandom(sb.NONCE_SIZE))

        msgC = "".join([b"c0:",
                        CIDToken,

# Path: src/petmail/errors.py
# class ReplayError(Exception):
#     pass
# 
# class WrongVerfkeyError(Exception):
#     pass
# 
# class UnknownChannelError(Exception):
#     """Message not decryptable by any of our channels."""
# 
# Path: src/petmail/util.py
# def split_into(s, piece_sizes, plus_trailer=False):
#     assert type(s) == type(b"")
#     pieces = []
#     piece_start = 0
#     for size in piece_sizes:
#         piece_end = piece_start+size
#         pieces.append(s[piece_start:piece_end])
#         piece_start = piece_end
#     if plus_trailer:
#         pieces.append(s[piece_start:])
#     else:
#         if piece_start != len(s):
#             raise ValueError("split did not consume entire string")
#     return pieces
# 
# def verify_with_prefix(vk, sm, prefix):
#     m = vk.verify(sm)
#     if not m.startswith(prefix):
#         raise BadSignatureError("missing expected prefix")
#     return m[len(prefix):]
# 
# Path: src/petmail/hkdf.py
# def HKDF(IKM, dkLen, salt=None, info=b"", digest=sha256,
#          _test_expected_PRK=None):
#     assert isinstance(IKM, bytes)
#     assert isinstance(salt, (bytes,type(None)))
#     assert isinstance(info, bytes)
#     hlen = len(digest(b"").digest())
#     assert dkLen <= hlen*255
#     if salt is None:
#         salt = b"\x00"*hlen
#     # extract
#     PRK = hmac.new(salt, IKM, digest).digest()
#     if _test_expected_PRK and _test_expected_PRK != PRK:
#         raise ValueError("test failed")
#     # expand
#     blocks = []
#     counter = 1
#     t = b""
#     while hlen*len(blocks) < dkLen:
#         t = hmac.new(PRK, t+info+chr(counter), digest).digest()
#         blocks.append(t)
#         counter += 1
#     return b"".join(blocks)[:dkLen]
# 
# Path: src/petmail/netstring.py
# def netstring(msg):
#     assert isinstance(msg, str)
#     return "%d:%s," % (len(msg), msg)
# 
# def split_netstrings_and_trailer(s):
#     p = _NetstringParser()
#     p.messages = messages = []
#     p.makeConnection(_EmptyTransport())
#     p.dataReceived(s)
#     return (messages, p._remainingData)
# 
# Path: src/petmail/mailbox/delivery.py
# class OutboundHTTPTransport:
#     """I call mailbox.transport to create msgA, then perform an HTTP POST to a
#     mailbox server."""
#     def __init__(self, db, trecord):
#         self.db = db
#         self.trecord = trecord
# 
#     def send(self, msgC):
#         msgA = createMsgA(self.trecord, msgC)
#         url = str(self.trecord["url"])
#         return client.getPage(url, method="POST", postdata=msgA)
# 
# class ReturnTransport: # for tests
#     """I call mailbox.transport to create msgA, then return it."""
#     def __init__(self, db, trecord):
#         self.db = db
#         self.trecord = trecord
# 
#     def send(self, msgC):
#         msgA = createMsgA(self.trecord, msgC)
#         return defer.succeed(msgA)


# Path: src/petmail/mailbox/channel.py
import struct, json, os
from hashlib import sha256
from twisted.internet import defer
from ..errors import ReplayError, WrongVerfkeyError, UnknownChannelError
from ..util import split_into, verify_with_prefix
from ..hkdf import HKDF
from ..netstring import netstring, split_netstrings_and_trailer
from .delivery import OutboundHTTPTransport, ReturnTransport
from nacl.public import PrivateKey, PublicKey, Box
from nacl.signing import SigningKey, VerifyKey
from nacl.secret import SecretBox
from nacl.exceptions import CryptoError

        self.db.update("UPDATE addressbook SET next_outbound_seqnum=?"
                       " WHERE id=?",
                       (next_outbound_seqnum+1, self.cid),
                       "addressbook", self.cid)
        self.db.commit()
        seqnum_s = struct.pack(">Q", next_outbound_seqnum)
        my_signkey = SigningKey(res["my_signkey"].decode("hex"))
        privkey2 = PrivateKey.generate()
        pubkey2 = privkey2.public_key.encode()
        assert len(pubkey2) == 32
        crec = json.loads(res["their_channel_record_json"])
        channel_pubkey = crec["channel_pubkey"].decode("hex")
        channel_box = Box(privkey2, PublicKey(channel_pubkey))
        CIDKey = crec["CID_key"].decode("hex")

        authenticator = b"ce0:"+pubkey2
        msgE = "".join([seqnum_s,
                        netstring(my_signkey.sign(authenticator)),
                        json.dumps(payload).encode("utf-8"),
                        ])
        msgD = pubkey2 + channel_box.encrypt(msgE, os.urandom(Box.NONCE_SIZE))

        HmsgD = sha256(msgD).digest()
        CIDToken = build_CIDToken(CIDKey, next_outbound_seqnum)
        sb = SecretBox(CIDKey)
        CIDBox = sb.encrypt(seqnum_s+HmsgD+channel_pubkey,
                            os.urandom(sb.NONCE_SIZE))

        msgC = "".join([b"c0:",
                        CIDToken,

                        netstring(CIDBox),