# 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
    if known_channel_pubkey_s:
        keylist = filter_on_known_channel_pubkey(keylist,
                                                 known_channel_pubkey_s)
    return keylist

# then we trial-decrypt with all candidates
def decrypt_msgD(msgD, keylist):
    pubkey2_s, enc = split_into(msgD, [32], True)
    pubkey2 = PublicKey(pubkey2_s)
    for (privkey, keyid) in keylist:
        try:
            msgE = Box(privkey, pubkey2).decrypt(enc)
            return keyid, pubkey2_s, msgE
        except CryptoError:
            pass
    return None, None, None

def decrypt_CIDBox(CIDKey, CIDBox):
    sb = SecretBox(CIDKey)
    m = sb.decrypt(CIDBox) # may raise CryptoError
    seqnum_s,HmsgD,channel_pubkey_s = split_into(m, [8, 32, 32])
    seqnum = struct.unpack(">Q", seqnum_s)[0]
    return seqnum, HmsgD, channel_pubkey_s

# then validate on the way back out

def check_msgE(msgE, pubkey2_s, sender_verfkey_s, highest_seqnum):
    seqnum_s = msgE[:8]
    seqnum = struct.unpack(">Q", seqnum_s)[0]
    if seqnum <= highest_seqnum:

# 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

    if known_channel_pubkey_s:
        keylist = filter_on_known_channel_pubkey(keylist,
                                                 known_channel_pubkey_s)
    return keylist

# then we trial-decrypt with all candidates
def decrypt_msgD(msgD, keylist):
    pubkey2_s, enc = split_into(msgD, [32], True)
    pubkey2 = PublicKey(pubkey2_s)
    for (privkey, keyid) in keylist:
        try:
            msgE = Box(privkey, pubkey2).decrypt(enc)
            return keyid, pubkey2_s, msgE
        except CryptoError:
            pass
    return None, None, None

def decrypt_CIDBox(CIDKey, CIDBox):
    sb = SecretBox(CIDKey)
    m = sb.decrypt(CIDBox) # may raise CryptoError
    seqnum_s,HmsgD,channel_pubkey_s = split_into(m, [8, 32, 32])
    seqnum = struct.unpack(">Q", seqnum_s)[0]
    return seqnum, HmsgD, channel_pubkey_s

# then validate on the way back out

def check_msgE(msgE, pubkey2_s, sender_verfkey_s, highest_seqnum):
    seqnum_s = msgE[:8]
    seqnum = struct.unpack(">Q", seqnum_s)[0]
    if seqnum <= highest_seqnum:

        raise ReplayError()