1 | """ |
---|
2 | Ported to Python 3. |
---|
3 | """ |
---|
4 | from __future__ import annotations |
---|
5 | |
---|
6 | MODE_CHECK = "MODE_CHECK" # query all peers |
---|
7 | MODE_ANYTHING = "MODE_ANYTHING" # one recoverable version |
---|
8 | MODE_WRITE = "MODE_WRITE" # replace all shares, probably.. not for initial |
---|
9 | # creation |
---|
10 | MODE_READ = "MODE_READ" |
---|
11 | MODE_REPAIR = "MODE_REPAIR" # query all peers, get the privkey |
---|
12 | |
---|
13 | from allmydata.crypto import aes, rsa |
---|
14 | from allmydata.util import hashutil |
---|
15 | |
---|
16 | class NotWriteableError(Exception): |
---|
17 | pass |
---|
18 | |
---|
19 | class BadShareError(Exception): |
---|
20 | """This represents an error discovered in a particular share, during |
---|
21 | retrieve, from which we can recover by using some other share. This does |
---|
22 | *not* include local coding errors. |
---|
23 | """ |
---|
24 | |
---|
25 | class NeedMoreDataError(BadShareError): |
---|
26 | def __init__(self, needed_bytes, encprivkey_offset, encprivkey_length): |
---|
27 | Exception.__init__(self) |
---|
28 | self.needed_bytes = needed_bytes # up through EOF |
---|
29 | self.encprivkey_offset = encprivkey_offset |
---|
30 | self.encprivkey_length = encprivkey_length |
---|
31 | def __repr__(self): |
---|
32 | return "<NeedMoreDataError (%d bytes)>" % self.needed_bytes |
---|
33 | |
---|
34 | class UncoordinatedWriteError(Exception): |
---|
35 | def __repr__(self): |
---|
36 | return ("<%s -- You, oh user, tried to change a file or directory " |
---|
37 | "at the same time as another process was trying to change it. " |
---|
38 | " To avoid data loss, don't do this. Please see " |
---|
39 | "docs/write_coordination.rst for details.>" % |
---|
40 | (self.__class__.__name__,)) |
---|
41 | |
---|
42 | class UnrecoverableFileError(Exception): |
---|
43 | pass |
---|
44 | |
---|
45 | class NotEnoughServersError(Exception): |
---|
46 | """There were not enough functioning servers available to place shares |
---|
47 | upon. This might result from all servers being full or having an error, a |
---|
48 | local bug which causes all server requests to fail in the same way, or |
---|
49 | from there being zero servers. The first error received (if any) is |
---|
50 | stored in my .first_error attribute.""" |
---|
51 | def __init__(self, why, first_error=None): |
---|
52 | Exception.__init__(self, why, first_error) |
---|
53 | self.first_error = first_error |
---|
54 | |
---|
55 | class CorruptShareError(BadShareError): |
---|
56 | def __init__(self, server, shnum, reason): |
---|
57 | self.args = (server, shnum, reason) |
---|
58 | self.server = server |
---|
59 | self.shnum = shnum |
---|
60 | self.reason = reason |
---|
61 | def __str__(self): |
---|
62 | return "<CorruptShareError server=%r shnum[%d]: %s" % \ |
---|
63 | (self.server.get_name(), self.shnum, self.reason) |
---|
64 | |
---|
65 | class UnknownVersionError(BadShareError): |
---|
66 | """The share we received was of a version we don't recognize.""" |
---|
67 | |
---|
68 | |
---|
69 | def encrypt_privkey(writekey: bytes, privkey: bytes) -> bytes: |
---|
70 | """ |
---|
71 | For SSK, encrypt a private ("signature") key using the writekey. |
---|
72 | """ |
---|
73 | encryptor = aes.create_encryptor(writekey) |
---|
74 | crypttext = aes.encrypt_data(encryptor, privkey) |
---|
75 | return crypttext |
---|
76 | |
---|
77 | def decrypt_privkey(writekey: bytes, enc_privkey: bytes) -> bytes: |
---|
78 | """ |
---|
79 | The inverse of ``encrypt_privkey``. |
---|
80 | """ |
---|
81 | decryptor = aes.create_decryptor(writekey) |
---|
82 | privkey = aes.decrypt_data(decryptor, enc_privkey) |
---|
83 | return privkey |
---|
84 | |
---|
85 | def derive_mutable_keys(keypair: tuple[rsa.PublicKey, rsa.PrivateKey]) -> tuple[bytes, bytes, bytes]: |
---|
86 | """ |
---|
87 | Derive the SSK writekey, encrypted writekey, and fingerprint from the |
---|
88 | public/private ("verification" / "signature") keypair. |
---|
89 | """ |
---|
90 | pubkey, privkey = keypair |
---|
91 | pubkey_s = rsa.der_string_from_verifying_key(pubkey) |
---|
92 | privkey_s = rsa.der_string_from_signing_key(privkey) |
---|
93 | writekey = hashutil.ssk_writekey_hash(privkey_s) |
---|
94 | encprivkey = encrypt_privkey(writekey, privkey_s) |
---|
95 | fingerprint = hashutil.ssk_pubkey_fingerprint_hash(pubkey_s) |
---|
96 | return writekey, encprivkey, fingerprint |
---|