Marco Ricci commited on 2025-01-11 16:28:48
Zeige 3 geänderte Dateien mit 619 Einfügungen und 135 Löschungen.
We add all debug and info messages from the `derivepassphrase export vault` subcommand to the translatable strings enums. We also improve several debug messages from the "inline calculation" style to the more easily translatable "tabular listing of relevant data" style. Two unimportant info messages were dropped: * Attempting to parse as v0.2 configuration * Attempting to parse as v0.3 configuration
... | ... |
@@ -152,6 +152,7 @@ class TranslatedString: |
152 | 152 |
str |
153 | 153 |
| TranslatableString |
154 | 154 |
| Label |
155 |
+ | DebugMsgTemplate |
|
155 | 156 |
| InfoMsgTemplate |
156 | 157 |
| WarnMsgTemplate |
157 | 158 |
| ErrMsgTemplate |
... | ... |
@@ -161,7 +162,7 @@ class TranslatedString: |
161 | 162 |
**kwargs: Any, # noqa: ANN401 |
162 | 163 |
) -> None: |
163 | 164 |
if isinstance( |
164 |
- template, (Label, InfoMsgTemplate, WarnMsgTemplate, ErrMsgTemplate) |
|
165 |
+ template, (Label, DebugMsgTemplate, InfoMsgTemplate, WarnMsgTemplate, ErrMsgTemplate) |
|
165 | 166 |
): |
166 | 167 |
template = cast('TranslatableString', template.value) |
167 | 168 |
self.template = template |
... | ... |
@@ -781,7 +782,376 @@ class Label(enum.Enum): |
781 | 782 |
) |
782 | 783 |
|
783 | 784 |
|
785 |
+class DebugMsgTemplate(enum.Enum): |
|
786 |
+ BUCKET_ITEM_FOUND = _prepare_translatable( |
|
787 |
+ comments=r""" |
|
788 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
789 |
+ exporter for "storeroom"-type configuration directories. The |
|
790 |
+ system stores entries in different "buckets" of a hash table. |
|
791 |
+ Here, we report on a single item (path and value) we discovered |
|
792 |
+ after decrypting the whole bucket. (We ensure the path and |
|
793 |
+ value are printable as-is.) |
|
794 |
+ """, |
|
795 |
+ msg='Found bucket item: {path} -> {value}', |
|
796 |
+ context='debug message', |
|
797 |
+ flags='python-brace-format', |
|
798 |
+ ) |
|
799 |
+ DECRYPT_BUCKET_ITEM_INFO = _prepare_translatable( |
|
800 |
+ comments=r""" |
|
801 |
+ TRANSLATORS: "AES256-CBC" and "PKCS#7" are, in essence, names of |
|
802 |
+ formats, and should not be translated. "IV" means |
|
803 |
+ "initialization vector", and is specifically a cryptographic |
|
804 |
+ term, as are "plaintext" and "ciphertext". |
|
805 |
+ """, |
|
806 |
+ msg=""" |
|
807 |
+ Decrypt bucket item contents: |
|
808 |
+ |
|
809 |
+ \b |
|
810 |
+ Encryption key (master key): {enc_key} |
|
811 |
+ Encryption cipher: AES256-CBC with PKCS#7 padding |
|
812 |
+ Encryption IV: {iv} |
|
813 |
+ Encrypted ciphertext: {ciphertext} |
|
814 |
+ Plaintext: {plaintext} |
|
815 |
+ """, |
|
816 |
+ context='debug message', |
|
817 |
+ flags='python-brace-format', |
|
818 |
+ ) |
|
819 |
+ DECRYPT_BUCKET_ITEM_KEY_INFO = _prepare_translatable( |
|
820 |
+ msg=""" |
|
821 |
+ Decrypt bucket item: |
|
822 |
+ |
|
823 |
+ \b |
|
824 |
+ Plaintext: {plaintext} |
|
825 |
+ Encryption key (master key): {enc_key} |
|
826 |
+ Signing key (master key): {sign_key} |
|
827 |
+ """, |
|
828 |
+ comments='', |
|
829 |
+ context='debug message', |
|
830 |
+ flags='python-brace-format', |
|
831 |
+ ) |
|
832 |
+ DECRYPT_BUCKET_ITEM_MAC_INFO = _prepare_translatable( |
|
833 |
+ comments=r""" |
|
834 |
+ TRANSLATORS: The MAC stands for "message authentication code", |
|
835 |
+ which guarantees the authenticity of the message to anyone who |
|
836 |
+ holds the corresponding key, similar to a digital signature. |
|
837 |
+ The acronym "MAC" is assumed to be well-known to the English |
|
838 |
+ target audience, or at least discoverable by them; they *are* |
|
839 |
+ asking for debug output, after all. Please use your judgement |
|
840 |
+ as to whether to translate this term or not, expanded or not. |
|
841 |
+ """, |
|
842 |
+ msg=""" |
|
843 |
+ Decrypt bucket item contents: |
|
844 |
+ |
|
845 |
+ \b |
|
846 |
+ MAC key: {sign_key} |
|
847 |
+ Authenticated content: {ciphertext} |
|
848 |
+ Claimed MAC value: {claimed_mac} |
|
849 |
+ Computed MAC value: {actual_mac} |
|
850 |
+ """, |
|
851 |
+ context='debug message', |
|
852 |
+ flags='python-brace-format', |
|
853 |
+ ) |
|
854 |
+ DECRYPT_BUCKET_ITEM_SESSION_KEYS_INFO = _prepare_translatable( |
|
855 |
+ comments=r""" |
|
856 |
+ TRANSLATORS: "AES256-CBC" and "PKCS#7" are, in essence, names of |
|
857 |
+ formats, and should not be translated. "IV" means |
|
858 |
+ "initialization vector", and is specifically a cryptographic |
|
859 |
+ term, as are "plaintext" and "ciphertext". |
|
860 |
+ """, |
|
861 |
+ msg=""" |
|
862 |
+ Decrypt bucket item session keys: |
|
863 |
+ |
|
864 |
+ \b |
|
865 |
+ Encryption key (master key): {enc_key} |
|
866 |
+ Encryption cipher: AES256-CBC with PKCS#7 padding |
|
867 |
+ Encryption IV: {iv} |
|
868 |
+ Encrypted ciphertext: {ciphertext} |
|
869 |
+ Plaintext: {plaintext} |
|
870 |
+ Parsed plaintext: {code} |
|
871 |
+ """, |
|
872 |
+ context='debug message', |
|
873 |
+ flags='python-brace-format', |
|
874 |
+ ) |
|
875 |
+ DECRYPT_BUCKET_ITEM_SESSION_KEYS_MAC_INFO = _prepare_translatable( |
|
876 |
+ comments=r""" |
|
877 |
+ TRANSLATORS: The MAC stands for "message authentication code", |
|
878 |
+ which guarantees the authenticity of the message to anyone who |
|
879 |
+ holds the corresponding key, similar to a digital signature. |
|
880 |
+ The acronym "MAC" is assumed to be well-known to the English |
|
881 |
+ target audience, or at least discoverable by them; they *are* |
|
882 |
+ asking for debug output, after all. Please use your judgement |
|
883 |
+ as to whether to translate this term or not, expanded or not. |
|
884 |
+ """, |
|
885 |
+ msg=""" |
|
886 |
+ Decrypt bucket item session keys: |
|
887 |
+ |
|
888 |
+ \b |
|
889 |
+ MAC key (master key): {sign_key} |
|
890 |
+ Authenticated content: {ciphertext} |
|
891 |
+ Claimed MAC value: {claimed_mac} |
|
892 |
+ Computed MAC value: {actual_mac} |
|
893 |
+ """, |
|
894 |
+ context='debug message', |
|
895 |
+ flags='python-brace-format', |
|
896 |
+ ) |
|
897 |
+ DERIVED_MASTER_KEYS_KEYS = _prepare_translatable( |
|
898 |
+ msg=""" |
|
899 |
+ Derived master keys' keys: |
|
900 |
+ |
|
901 |
+ \b |
|
902 |
+ Encryption key: {enc_key} |
|
903 |
+ Signing key: {sign_key} |
|
904 |
+ Password: {pw_bytes} |
|
905 |
+ Function call: pbkdf2(algorithm={algorithm!r}, length={length!r}, salt={salt!r}, iterations={iterations!r}) |
|
906 |
+ |
|
907 |
+ """, # noqa: E501 |
|
908 |
+ comments='', |
|
909 |
+ context='debug message', |
|
910 |
+ flags='python-brace-format', |
|
911 |
+ ) |
|
912 |
+ DIRECTORY_CONTENTS_CHECK_OK = _prepare_translatable( |
|
913 |
+ comments=r""" |
|
914 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
915 |
+ exporter for "storeroom"-type configuration directories, while |
|
916 |
+ "assembling" the items stored in the configuration according to |
|
917 |
+ the item's "path". Each "directory" in the path contains a list |
|
918 |
+ of children it claims to contain, and this list must be matched |
|
919 |
+ against the actual discovered items. Now, at the end, we |
|
920 |
+ actually confirm the claim. (We would have already thrown an |
|
921 |
+ error here otherwise.) |
|
922 |
+ """, |
|
923 |
+ msg='Directory contents check OK: {path} -> {contents}', |
|
924 |
+ context='debug message', |
|
925 |
+ flags='python-brace-format', |
|
926 |
+ ) |
|
927 |
+ MASTER_KEYS_DATA_MAC_INFO = _prepare_translatable( |
|
928 |
+ comments=r""" |
|
929 |
+ TRANSLATORS: The MAC stands for "message authentication code", |
|
930 |
+ which guarantees the authenticity of the message to anyone who |
|
931 |
+ holds the corresponding key, similar to a digital signature. |
|
932 |
+ The acronym "MAC" is assumed to be well-known to the English |
|
933 |
+ target audience, or at least discoverable by them; they *are* |
|
934 |
+ asking for debug output, after all. Please use your judgement |
|
935 |
+ as to whether to translate this term or not, expanded or not. |
|
936 |
+ """, |
|
937 |
+ msg=""" |
|
938 |
+ Master keys data: |
|
939 |
+ |
|
940 |
+ \b |
|
941 |
+ MAC key: {sign_key} |
|
942 |
+ Authenticated content: {ciphertext} |
|
943 |
+ Claimed MAC value: {claimed_mac} |
|
944 |
+ Computed MAC value: {actual_mac} |
|
945 |
+ """, |
|
946 |
+ context='debug message', |
|
947 |
+ flags='python-brace-format', |
|
948 |
+ ) |
|
949 |
+ POSTPONING_DIRECTORY_CONTENTS_CHECK = _prepare_translatable( |
|
950 |
+ comments=r""" |
|
951 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
952 |
+ exporter for "storeroom"-type configuration directories, while |
|
953 |
+ "assembling" the items stored in the configuration according to |
|
954 |
+ the item's "path". Each "directory" in the path contains a list |
|
955 |
+ of children it claims to contain, and this list must be matched |
|
956 |
+ against the actual discovered items. When emitting this |
|
957 |
+ message, we merely indicate that we saved the "claimed" list for |
|
958 |
+ this directory for later. |
|
959 |
+ """, |
|
960 |
+ msg='Postponing directory contents check: {path} -> {contents}', |
|
961 |
+ context='debug message', |
|
962 |
+ flags='python-brace-format', |
|
963 |
+ ) |
|
964 |
+ SETTING_CONFIG_STRUCTURE_CONTENTS = _prepare_translatable( |
|
965 |
+ comments=r""" |
|
966 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
967 |
+ exporter for "storeroom"-type configuration directories, while |
|
968 |
+ "assembling" the items stored in the configuration according to |
|
969 |
+ the item's "path". We confirm that we set the entry at the |
|
970 |
+ given path to the given value. |
|
971 |
+ """, |
|
972 |
+ msg='Setting contents: {path} -> {value}', |
|
973 |
+ context='debug message', |
|
974 |
+ flags='python-brace-format', |
|
975 |
+ ) |
|
976 |
+ SETTING_CONFIG_STRUCTURE_CONTENTS_EMPTY_DIRECTORY = _prepare_translatable( |
|
977 |
+ comments=r""" |
|
978 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
979 |
+ exporter for "storeroom"-type configuration directories, while |
|
980 |
+ "assembling" the items stored in the configuration according to |
|
981 |
+ the item's "path". We confirm that we set up a currently empty |
|
982 |
+ directory at the given path. |
|
983 |
+ """, |
|
984 |
+ msg='Setting contents (empty directory): {path}', |
|
985 |
+ context='debug message', |
|
986 |
+ flags='python-brace-format', |
|
987 |
+ ) |
|
988 |
+ VAULT_NATIVE_EVP_BYTESTOKEY_INIT = _prepare_translatable( |
|
989 |
+ comments=r""" |
|
990 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
991 |
+ exporter for "native"-type configuration directories: in v0.2, |
|
992 |
+ the non-standard and deprecated "EVP_bytestokey" function from |
|
993 |
+ OpenSSL must be reimplemented from scratch. The terms "salt" |
|
994 |
+ and "IV" (initialization vector) are cryptographic terms. |
|
995 |
+ """, |
|
996 |
+ msg=""" |
|
997 |
+ evp_bytestokey_md5 (initialization): |
|
998 |
+ |
|
999 |
+ \b |
|
1000 |
+ Input: {data} |
|
1001 |
+ Salt: {salt} |
|
1002 |
+ Key size: {key_size} |
|
1003 |
+ IV size: {iv_size} |
|
1004 |
+ Buffer length: {buffer_length} |
|
1005 |
+ Buffer: {buffer} |
|
1006 |
+ """, |
|
1007 |
+ context='debug message', |
|
1008 |
+ flags='python-brace-format', |
|
1009 |
+ ) |
|
1010 |
+ VAULT_NATIVE_EVP_BYTESTOKEY_RESULT = _prepare_translatable( |
|
1011 |
+ comments=r""" |
|
1012 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1013 |
+ exporter for "native"-type configuration directories: in v0.2, |
|
1014 |
+ the non-standard and deprecated "EVP_bytestokey" function from |
|
1015 |
+ OpenSSL must be reimplemented from scratch. The terms "salt" |
|
1016 |
+ and "IV" (initialization vector) are cryptographic terms. |
|
1017 |
+ This function reports on the updated buffer length and contents |
|
1018 |
+ after executing one round of hashing. |
|
1019 |
+ """, |
|
1020 |
+ msg=""" |
|
1021 |
+ evp_bytestokey_md5 (result): |
|
1022 |
+ |
|
1023 |
+ \b |
|
1024 |
+ Encryption key: {enc_key} |
|
1025 |
+ IV: {iv} |
|
1026 |
+ """, |
|
1027 |
+ context='debug message', |
|
1028 |
+ flags='python-brace-format', |
|
1029 |
+ ) |
|
1030 |
+ VAULT_NATIVE_EVP_BYTESTOKEY_ROUND = _prepare_translatable( |
|
1031 |
+ comments=r""" |
|
1032 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1033 |
+ exporter for "native"-type configuration directories: in v0.2, |
|
1034 |
+ the non-standard and deprecated "EVP_bytestokey" function from |
|
1035 |
+ OpenSSL must be reimplemented from scratch. The terms "salt" |
|
1036 |
+ and "IV" (initialization vector) are cryptographic terms. |
|
1037 |
+ This function reports on the updated buffer length and contents |
|
1038 |
+ after executing one round of hashing. |
|
1039 |
+ """, |
|
1040 |
+ msg=""" |
|
1041 |
+ evp_bytestokey_md5 (round update): |
|
1042 |
+ |
|
1043 |
+ \b |
|
1044 |
+ Buffer length: {buffer_length} |
|
1045 |
+ Buffer: {buffer} |
|
1046 |
+ """, |
|
1047 |
+ context='debug message', |
|
1048 |
+ flags='python-brace-format', |
|
1049 |
+ ) |
|
1050 |
+ VAULT_NATIVE_CHECKING_MAC_DETAILS = _prepare_translatable( |
|
1051 |
+ comments=r""" |
|
1052 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1053 |
+ exporter for "native"-type configuration directories. It is |
|
1054 |
+ preceded by the info message PARSING_IV_PAYLOAD_MAC; see the |
|
1055 |
+ commentary there concerning the terms and thoughts on |
|
1056 |
+ translating them. |
|
1057 |
+ """, |
|
1058 |
+ msg=""" |
|
1059 |
+ MAC details: |
|
1060 |
+ |
|
1061 |
+ \b |
|
1062 |
+ MAC input: {mac_input} |
|
1063 |
+ Expected MAC: {mac} |
|
1064 |
+ """, |
|
1065 |
+ context='debug message', |
|
1066 |
+ flags='python-brace-format', |
|
1067 |
+ ) |
|
1068 |
+ VAULT_NATIVE_PADDED_PLAINTEXT = _prepare_translatable( |
|
1069 |
+ comments=r""" |
|
1070 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1071 |
+ exporter for "native"-type configuration directories. "padding" |
|
1072 |
+ and "plaintext" are cryptographic terms. |
|
1073 |
+ """, |
|
1074 |
+ msg='Padded plaintext: {contents}', |
|
1075 |
+ context='debug message', |
|
1076 |
+ flags='python-brace-format', |
|
1077 |
+ ) |
|
1078 |
+ VAULT_NATIVE_PARSE_BUFFER = _prepare_translatable( |
|
1079 |
+ comments=r""" |
|
1080 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1081 |
+ exporter for "native"-type configuration directories. It is |
|
1082 |
+ preceded by the info message PARSING_IV_PAYLOAD_MAC; see the |
|
1083 |
+ commentary there concerning the terms and thoughts on |
|
1084 |
+ translating them. |
|
1085 |
+ """, |
|
1086 |
+ msg=""" |
|
1087 |
+ Buffer: {contents} |
|
1088 |
+ |
|
1089 |
+ \b |
|
1090 |
+ IV: {iv} |
|
1091 |
+ Payload: {payload} |
|
1092 |
+ MAC: {mac} |
|
1093 |
+ """, |
|
1094 |
+ context='debug message', |
|
1095 |
+ flags='python-brace-format', |
|
1096 |
+ ) |
|
1097 |
+ VAULT_NATIVE_PLAINTEXT = _prepare_translatable( |
|
1098 |
+ comments=r""" |
|
1099 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1100 |
+ exporter for "native"-type configuration directories. |
|
1101 |
+ "plaintext" is a cryptographic term. |
|
1102 |
+ """, |
|
1103 |
+ msg='Plaintext: {contents}', |
|
1104 |
+ context='debug message', |
|
1105 |
+ flags='python-brace-format', |
|
1106 |
+ ) |
|
1107 |
+ VAULT_NATIVE_PBKDF2_CALL = _prepare_translatable( |
|
1108 |
+ msg=""" |
|
1109 |
+ Master key derivation: |
|
1110 |
+ |
|
1111 |
+ \b |
|
1112 |
+ PBKDF2 call: PBKDF2-HMAC(password={password!r}, salt={salt!r}, iterations={iterations!r}, key_size={key_size!r}, algorithm={algorithm!r}) |
|
1113 |
+ Result (binary): {raw_result} |
|
1114 |
+ Result (hex key): {result_key!r} |
|
1115 |
+ """, # noqa: E501 |
|
1116 |
+ comments='', |
|
1117 |
+ context='debug message', |
|
1118 |
+ flags='python-brace-format', |
|
1119 |
+ ) |
|
1120 |
+ VAULT_NATIVE_V02_PAYLOAD_MAC_POSTPROCESSING = _prepare_translatable( |
|
1121 |
+ comments=r""" |
|
1122 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1123 |
+ exporter for "native"-type configuration directories. It is |
|
1124 |
+ preceded by the info message PARSING_IV_PAYLOAD_MAC and the |
|
1125 |
+ debug message PARSING_NATIVE_PARSE_BUFFER; see the commentary |
|
1126 |
+ there concerning the terms and thoughts on translating them. |
|
1127 |
+ """, |
|
1128 |
+ msg=""" |
|
1129 |
+ Postprocessing buffer (v0.2): |
|
1130 |
+ |
|
1131 |
+ \b |
|
1132 |
+ Payload: {payload} (decoded from base64) |
|
1133 |
+ MAC: {mac} (decoded from hex) |
|
1134 |
+ """, |
|
1135 |
+ context='debug message', |
|
1136 |
+ flags='python-brace-format', |
|
1137 |
+ ) |
|
1138 |
+ |
|
1139 |
+ |
|
784 | 1140 |
class InfoMsgTemplate(enum.Enum): |
1141 |
+ ASSEMBLING_CONFIG_STRUCTURE = _prepare_translatable( |
|
1142 |
+ comments=r""" |
|
1143 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1144 |
+ exporter for "storeroom"-type configuration directories. The |
|
1145 |
+ system stores entries in different "buckets" of a hash table. |
|
1146 |
+ After the respective items in the buckets have been decrypted, |
|
1147 |
+ we then have a list of item paths plus contents to populate. |
|
1148 |
+ This must be done in a certain order (we don't yet have an |
|
1149 |
+ existing directory tree to rely on, but rather must build it |
|
1150 |
+ on-the-fly), hence the term "assembling". |
|
1151 |
+ """, |
|
1152 |
+ msg='Assembling config structure', |
|
1153 |
+ context='info message', |
|
1154 |
+ ) |
|
785 | 1155 |
CANNOT_LOAD_AS_VAULT_CONFIG = _prepare_translatable( |
786 | 1156 |
comments=r""" |
787 | 1157 |
TRANSLATORS: "fmt" is a string such as "v0.2" or "storeroom", |
... | ... |
@@ -792,6 +1162,40 @@ class InfoMsgTemplate(enum.Enum): |
792 | 1162 |
context='info message', |
793 | 1163 |
flags='python-brace-format', |
794 | 1164 |
) |
1165 |
+ CHECKING_CONFIG_STRUCTURE_CONSISTENCY = _prepare_translatable( |
|
1166 |
+ comments=r""" |
|
1167 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1168 |
+ exporter for "storeroom"-type configuration directories. Having |
|
1169 |
+ "assembled" the configuration items according to their claimed |
|
1170 |
+ paths and contents, we then check if the assembled structure is |
|
1171 |
+ internally consistent. |
|
1172 |
+ """, |
|
1173 |
+ msg='Checking config structure consistency', |
|
1174 |
+ context='info message', |
|
1175 |
+ ) |
|
1176 |
+ DECRYPTING_BUCKET = _prepare_translatable( |
|
1177 |
+ comments=r""" |
|
1178 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1179 |
+ exporter for "storeroom"-type configuration directories. The |
|
1180 |
+ system stores entries in different "buckets" of a hash table. |
|
1181 |
+ We parse the directory bucket by bucket. All buckets are |
|
1182 |
+ numbered in hexadecimal, and typically there are 32 buckets, so |
|
1183 |
+ 2-digit hex numbers. |
|
1184 |
+ """, |
|
1185 |
+ msg='Decrypting bucket {bucket_number}', |
|
1186 |
+ context='info message', |
|
1187 |
+ flags='python-brace-format', |
|
1188 |
+ ) |
|
1189 |
+ PARSING_MASTER_KEYS_DATA = _prepare_translatable( |
|
1190 |
+ comments=r""" |
|
1191 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1192 |
+ exporter for "storeroom"-type configuration directories. |
|
1193 |
+ `.keys` is a filename, from which data about the master keys for |
|
1194 |
+ this configuration are loaded. |
|
1195 |
+ """, |
|
1196 |
+ msg='Parsing master keys data from .keys', |
|
1197 |
+ context='info message', |
|
1198 |
+ ) |
|
795 | 1199 |
PIP_INSTALL_EXTRA = _prepare_translatable( |
796 | 1200 |
comments=r""" |
797 | 1201 |
TRANSLATORS: This message immediately follows an error message |
... | ... |
@@ -815,6 +1219,36 @@ class InfoMsgTemplate(enum.Enum): |
815 | 1219 |
context='info message', |
816 | 1220 |
flags='python-brace-format', |
817 | 1221 |
) |
1222 |
+ VAULT_NATIVE_CHECKING_MAC = _prepare_translatable( |
|
1223 |
+ msg='Checking MAC', |
|
1224 |
+ comments='', |
|
1225 |
+ context='info message', |
|
1226 |
+ ) |
|
1227 |
+ VAULT_NATIVE_DECRYPTING_CONTENTS = _prepare_translatable( |
|
1228 |
+ msg='Decrypting contents', |
|
1229 |
+ comments='', |
|
1230 |
+ context='info message', |
|
1231 |
+ ) |
|
1232 |
+ VAULT_NATIVE_DERIVING_KEYS = _prepare_translatable( |
|
1233 |
+ msg='Deriving an encryption and signing key', |
|
1234 |
+ comments='', |
|
1235 |
+ context='info message', |
|
1236 |
+ ) |
|
1237 |
+ VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC = _prepare_translatable( |
|
1238 |
+ comments=r""" |
|
1239 |
+ TRANSLATORS: This message is emitted by the vault configuration |
|
1240 |
+ exporter for "native"-type configuration directories. "IV" |
|
1241 |
+ means "initialization vector", and "MAC" means "message |
|
1242 |
+ authentication code". They are specifically cryptographic |
|
1243 |
+ terms, as is "payload". The acronyms "IV" and "MAC" are assumed |
|
1244 |
+ to be well-known to the English target audience, or at least |
|
1245 |
+ discoverable by them; they *are* asking for debug output, after |
|
1246 |
+ all. Please use your judgement as to whether to translate this |
|
1247 |
+ term or not, expanded or not. |
|
1248 |
+ """, |
|
1249 |
+ msg='Parsing IV, payload and MAC from the file contents', |
|
1250 |
+ context='info message', |
|
1251 |
+ ) |
|
818 | 1252 |
|
819 | 1253 |
|
820 | 1254 |
class WarnMsgTemplate(enum.Enum): |
... | ... |
@@ -1250,11 +1684,12 @@ def _write_pot_file(fileobj: TextIO) -> None: # pragma: no cover |
1250 | 1684 |
str, |
1251 | 1685 |
dict[ |
1252 | 1686 |
str, |
1253 |
- Label | InfoMsgTemplate | WarnMsgTemplate | ErrMsgTemplate, |
|
1687 |
+ Label | DebugMsgTemplate | InfoMsgTemplate | WarnMsgTemplate | ErrMsgTemplate, |
|
1254 | 1688 |
], |
1255 | 1689 |
] = {} |
1256 | 1690 |
for enum_class in ( |
1257 | 1691 |
Label, |
1692 |
+ DebugMsgTemplate, |
|
1258 | 1693 |
InfoMsgTemplate, |
1259 | 1694 |
WarnMsgTemplate, |
1260 | 1695 |
ErrMsgTemplate, |
... | ... |
@@ -1304,7 +1739,7 @@ def _write_pot_file(fileobj: TextIO) -> None: # pragma: no cover |
1304 | 1739 |
|
1305 | 1740 |
|
1306 | 1741 |
def _format_po_entry( |
1307 |
- enum_value: Label | InfoMsgTemplate | WarnMsgTemplate | ErrMsgTemplate, |
|
1742 |
+ enum_value: Label | DebugMsgTemplate | InfoMsgTemplate | WarnMsgTemplate | ErrMsgTemplate, |
|
1308 | 1743 |
) -> tuple[str, ...]: # pragma: no cover |
1309 | 1744 |
ret: list[str] = ['\n'] |
1310 | 1745 |
ts = enum_value.value |
... | ... |
@@ -31,6 +31,7 @@ import os.path |
31 | 31 |
import struct |
32 | 32 |
from typing import TYPE_CHECKING, Any, TypedDict |
33 | 33 |
|
34 |
+from derivepassphrase import _cli_msg as _msg |
|
34 | 35 |
from derivepassphrase import exporter |
35 | 36 |
|
36 | 37 |
if TYPE_CHECKING: |
... | ... |
@@ -39,6 +40,7 @@ if TYPE_CHECKING: |
39 | 40 |
from cryptography.hazmat.primitives import ciphers, hashes, hmac, padding |
40 | 41 |
from cryptography.hazmat.primitives.ciphers import algorithms, modes |
41 | 42 |
from cryptography.hazmat.primitives.kdf import pbkdf2 |
43 |
+ from typing_extensions import Buffer |
|
42 | 44 |
else: |
43 | 45 |
try: |
44 | 46 |
from cryptography.hazmat.primitives import ( |
... | ... |
@@ -79,6 +81,10 @@ __all__ = ('export_storeroom_data',) |
79 | 81 |
logger = logging.getLogger(__name__) |
80 | 82 |
|
81 | 83 |
|
84 |
+def _h(bs: Buffer) -> str: |
|
85 |
+ return '<{}>'.format(memoryview(bs).hex(' ')) |
|
86 |
+ |
|
87 |
+ |
|
82 | 88 |
class KeyPair(TypedDict): |
83 | 89 |
"""A pair of AES256 keys, one for encryption and one for signing. |
84 | 90 |
|
... | ... |
@@ -160,20 +166,16 @@ def derive_master_keys_keys(password: str | bytes, iterations: int) -> KeyPair: |
160 | 166 |
f'{KEY_SIZE}s {KEY_SIZE}s', master_keys_keys_blob |
161 | 167 |
) |
162 | 168 |
logger.debug( |
163 |
- ( |
|
164 |
- 'derived master_keys_keys bytes.fromhex(%s) (encryption) ' |
|
165 |
- 'and bytes.fromhex(%s) (signing) ' |
|
166 |
- 'from password bytes.fromhex(%s), ' |
|
167 |
- 'using call ' |
|
168 |
- 'pbkdf2(algorithm=%s, length=%d, salt=%s, iterations=%d)' |
|
169 |
+ _msg.TranslatedString( |
|
170 |
+ _msg.DebugMsgTemplate.DERIVED_MASTER_KEYS_KEYS, |
|
171 |
+ enc_key=_h(encryption_key), |
|
172 |
+ sign_key=_h(signing_key), |
|
173 |
+ pw_bytes=_h(password), |
|
174 |
+ algorithm='SHA256', |
|
175 |
+ length=64, |
|
176 |
+ salt=STOREROOM_MASTER_KEYS_UUID, |
|
177 |
+ iterations=iterations, |
|
169 | 178 |
), |
170 |
- repr(encryption_key.hex(' ')), |
|
171 |
- repr(signing_key.hex(' ')), |
|
172 |
- repr(password.hex(' ')), |
|
173 |
- repr('SHA256'), |
|
174 |
- 64, |
|
175 |
- repr(STOREROOM_MASTER_KEYS_UUID), |
|
176 |
- iterations, |
|
177 | 179 |
) |
178 | 180 |
return { |
179 | 181 |
'encryption_key': encryption_key, |
... | ... |
@@ -234,16 +236,13 @@ def decrypt_master_keys_data(data: bytes, keys: KeyPair) -> MasterKeys: |
234 | 236 |
actual_mac = hmac.HMAC(keys['signing_key'], hashes.SHA256()) |
235 | 237 |
actual_mac.update(ciphertext) |
236 | 238 |
logger.debug( |
237 |
- ( |
|
238 |
- 'master_keys_data mac_key = bytes.fromhex(%s), ' |
|
239 |
- 'hashed_content = bytes.fromhex(%s), ' |
|
240 |
- 'claimed_mac = bytes.fromhex(%s), ' |
|
241 |
- 'actual_mac = bytes.fromhex(%s)' |
|
239 |
+ _msg.TranslatedString( |
|
240 |
+ _msg.DebugMsgTemplate.MASTER_KEYS_DATA_MAC_INFO, |
|
241 |
+ sign_key=_h(keys['signing_key']), |
|
242 |
+ ciphertext=_h(ciphertext), |
|
243 |
+ claimed_mac=_h(claimed_mac), |
|
244 |
+ actual_mac=_h(actual_mac.copy().finalize()), |
|
242 | 245 |
), |
243 |
- repr(keys['signing_key'].hex(' ')), |
|
244 |
- repr(ciphertext.hex(' ')), |
|
245 |
- repr(claimed_mac.hex(' ')), |
|
246 |
- repr(actual_mac.copy().finalize().hex(' ')), |
|
247 | 246 |
) |
248 | 247 |
actual_mac.verify(claimed_mac) |
249 | 248 |
|
... | ... |
@@ -325,17 +324,13 @@ def decrypt_session_keys(data: bytes, master_keys: MasterKeys) -> KeyPair: |
325 | 324 |
actual_mac = hmac.HMAC(master_keys['signing_key'], hashes.SHA256()) |
326 | 325 |
actual_mac.update(ciphertext) |
327 | 326 |
logger.debug( |
328 |
- ( |
|
329 |
- 'decrypt_bucket_item (session_keys): ' |
|
330 |
- 'mac_key = bytes.fromhex(%s) (master), ' |
|
331 |
- 'hashed_content = bytes.fromhex(%s), ' |
|
332 |
- 'claimed_mac = bytes.fromhex(%s), ' |
|
333 |
- 'actual_mac = bytes.fromhex(%s)' |
|
327 |
+ _msg.TranslatedString( |
|
328 |
+ _msg.DebugMsgTemplate.DECRYPT_BUCKET_ITEM_SESSION_KEYS_MAC_INFO, |
|
329 |
+ sign_key=_h(master_keys['signing_key']), |
|
330 |
+ ciphertext=_h(ciphertext), |
|
331 |
+ claimed_mac=_h(claimed_mac), |
|
332 |
+ actual_mac=_h(actual_mac.copy().finalize()), |
|
334 | 333 |
), |
335 |
- repr(master_keys['signing_key'].hex(' ')), |
|
336 |
- repr(ciphertext.hex(' ')), |
|
337 |
- repr(claimed_mac.hex(' ')), |
|
338 |
- repr(actual_mac.copy().finalize().hex(' ')), |
|
339 | 334 |
) |
340 | 335 |
actual_mac.verify(claimed_mac) |
341 | 336 |
|
... | ... |
@@ -366,20 +361,19 @@ def decrypt_session_keys(data: bytes, master_keys: MasterKeys) -> KeyPair: |
366 | 361 |
} |
367 | 362 |
|
368 | 363 |
logger.debug( |
369 |
- ( |
|
370 |
- 'decrypt_bucket_item (session_keys): ' |
|
371 |
- 'decrypt_aes256_cbc_and_unpad(key=bytes.fromhex(%s), ' |
|
372 |
- 'iv=bytes.fromhex(%s))(bytes.fromhex(%s)) ' |
|
373 |
- '= bytes.fromhex(%s) ' |
|
374 |
- '= {"encryption_key": bytes.fromhex(%s), ' |
|
375 |
- '"signing_key": bytes.fromhex(%s)}' |
|
364 |
+ _msg.TranslatedString( |
|
365 |
+ _msg.DebugMsgTemplate.DECRYPT_BUCKET_ITEM_SESSION_KEYS_INFO, |
|
366 |
+ enc_key=_h(master_keys['encryption_key']), |
|
367 |
+ iv=_h(iv), |
|
368 |
+ ciphertext=_h(payload), |
|
369 |
+ plaintext=_h(plaintext), |
|
370 |
+ code=_msg.TranslatedString( |
|
371 |
+ '{{"encryption_key": bytes.fromhex({enc_key!r}), ' |
|
372 |
+ '"signing_key": bytes.fromhex({sign_key!r})}}', |
|
373 |
+ enc_key=session_keys['encryption_key'].hex(' '), |
|
374 |
+ sign_key=session_keys['signing_key'].hex(' '), |
|
375 |
+ ), |
|
376 | 376 |
), |
377 |
- repr(master_keys['encryption_key'].hex(' ')), |
|
378 |
- repr(iv.hex(' ')), |
|
379 |
- repr(payload.hex(' ')), |
|
380 |
- repr(plaintext.hex(' ')), |
|
381 |
- repr(session_keys['encryption_key'].hex(' ')), |
|
382 |
- repr(session_keys['signing_key'].hex(' ')), |
|
383 | 377 |
) |
384 | 378 |
|
385 | 379 |
return session_keys |
... | ... |
@@ -432,17 +426,13 @@ def decrypt_contents(data: bytes, session_keys: KeyPair) -> bytes: |
432 | 426 |
actual_mac = hmac.HMAC(session_keys['signing_key'], hashes.SHA256()) |
433 | 427 |
actual_mac.update(ciphertext) |
434 | 428 |
logger.debug( |
435 |
- ( |
|
436 |
- 'decrypt_bucket_item (contents): ' |
|
437 |
- 'mac_key = bytes.fromhex(%s), ' |
|
438 |
- 'hashed_content = bytes.fromhex(%s), ' |
|
439 |
- 'claimed_mac = bytes.fromhex(%s), ' |
|
440 |
- 'actual_mac = bytes.fromhex(%s)' |
|
429 |
+ _msg.TranslatedString( |
|
430 |
+ _msg.DebugMsgTemplate.DECRYPT_BUCKET_ITEM_MAC_INFO, |
|
431 |
+ sign_key=_h(session_keys['signing_key']), |
|
432 |
+ ciphertext=_h(ciphertext), |
|
433 |
+ claimed_mac=_h(claimed_mac), |
|
434 |
+ actual_mac=_h(actual_mac.copy().finalize()), |
|
441 | 435 |
), |
442 |
- repr(session_keys['signing_key'].hex(' ')), |
|
443 |
- repr(ciphertext.hex(' ')), |
|
444 |
- repr(claimed_mac.hex(' ')), |
|
445 |
- repr(actual_mac.copy().finalize().hex(' ')), |
|
446 | 436 |
) |
447 | 437 |
actual_mac.verify(claimed_mac) |
448 | 438 |
|
... | ... |
@@ -461,16 +451,13 @@ def decrypt_contents(data: bytes, session_keys: KeyPair) -> bytes: |
461 | 451 |
plaintext.extend(unpadder.finalize()) |
462 | 452 |
|
463 | 453 |
logger.debug( |
464 |
- ( |
|
465 |
- 'decrypt_bucket_item (contents): ' |
|
466 |
- 'decrypt_aes256_cbc_and_unpad(key=bytes.fromhex(%s), ' |
|
467 |
- 'iv=bytes.fromhex(%s))(bytes.fromhex(%s)) ' |
|
468 |
- '= bytes.fromhex(%s)' |
|
454 |
+ _msg.TranslatedString( |
|
455 |
+ _msg.DebugMsgTemplate.DECRYPT_BUCKET_ITEM_INFO, |
|
456 |
+ enc_key=_h(session_keys['encryption_key']), |
|
457 |
+ iv=_h(iv), |
|
458 |
+ ciphertext=_h(payload), |
|
459 |
+ plaintext=_h(plaintext), |
|
469 | 460 |
), |
470 |
- repr(session_keys['encryption_key'].hex(' ')), |
|
471 |
- repr(iv.hex(' ')), |
|
472 |
- repr(payload.hex(' ')), |
|
473 |
- repr(plaintext.hex(' ')), |
|
474 | 461 |
) |
475 | 462 |
|
476 | 463 |
return plaintext |
... | ... |
@@ -505,14 +492,12 @@ def decrypt_bucket_item(bucket_item: bytes, master_keys: MasterKeys) -> bytes: |
505 | 492 |
|
506 | 493 |
""" |
507 | 494 |
logger.debug( |
508 |
- ( |
|
509 |
- 'decrypt_bucket_item: data = bytes.fromhex(%s), ' |
|
510 |
- 'encryption_key = bytes.fromhex(%s), ' |
|
511 |
- 'signing_key = bytes.fromhex(%s)' |
|
495 |
+ _msg.TranslatedString( |
|
496 |
+ _msg.DebugMsgTemplate.DECRYPT_BUCKET_ITEM_KEY_INFO, |
|
497 |
+ plaintext=_h(bucket_item), |
|
498 |
+ enc_key=_h(master_keys['encryption_key']), |
|
499 |
+ sign_key=_h(master_keys['signing_key']), |
|
512 | 500 |
), |
513 |
- repr(bucket_item.hex(' ')), |
|
514 |
- repr(master_keys['encryption_key'].hex(' ')), |
|
515 |
- repr(master_keys['signing_key'].hex(' ')), |
|
516 | 501 |
) |
517 | 502 |
data_version, encrypted_session_keys, data_contents = struct.unpack( |
518 | 503 |
( |
... | ... |
@@ -665,7 +650,9 @@ def export_storeroom_data( # noqa: C901,PLR0912,PLR0914,PLR0915 |
665 | 650 |
if encrypted_keys_version != 1: |
666 | 651 |
msg = f'cannot handle version {encrypted_keys_version} encrypted keys' |
667 | 652 |
raise RuntimeError(msg) |
668 |
- logger.info('Parsing master keys data from .keys') |
|
653 |
+ logger.info( |
|
654 |
+ _msg.TranslatedString(_msg.InfoMsgTemplate.PARSING_MASTER_KEYS_DATA) |
|
655 |
+ ) |
|
669 | 656 |
encrypted_keys_iterations = 2 ** (10 + (encrypted_keys_params & 0x0F)) |
670 | 657 |
master_keys_keys = derive_master_keys_keys( |
671 | 658 |
master_keys_key, encrypted_keys_iterations |
... | ... |
@@ -683,7 +670,12 @@ def export_storeroom_data( # noqa: C901,PLR0912,PLR0914,PLR0915 |
683 | 670 |
if fnmatch.fnmatch(hashdir_name, '[01][0-9a-f]') |
684 | 671 |
] |
685 | 672 |
for file in valid_hashdirs: |
686 |
- logger.info('Decrypting bucket %s', file) |
|
673 |
+ logger.info( |
|
674 |
+ _msg.TranslatedString( |
|
675 |
+ _msg.InfoMsgTemplate.DECRYPTING_BUCKET, |
|
676 |
+ bucket_number=file, |
|
677 |
+ ) |
|
678 |
+ ) |
|
687 | 679 |
bucket_contents = list( |
688 | 680 |
decrypt_bucket_file(file, master_keys, root_dir=storeroom_path) |
689 | 681 |
) |
... | ... |
@@ -691,17 +683,25 @@ def export_storeroom_data( # noqa: C901,PLR0912,PLR0914,PLR0915 |
691 | 683 |
for pos, item in enumerate(bucket_index): |
692 | 684 |
json_contents[item] = bucket_contents[pos] |
693 | 685 |
logger.debug( |
694 |
- 'Found bucket item: %s -> %s', item, bucket_contents[pos] |
|
686 |
+ _msg.TranslatedString( |
|
687 |
+ _msg.DebugMsgTemplate.BUCKET_ITEM_FOUND, |
|
688 |
+ path=item, |
|
689 |
+ value=bucket_contents[pos], |
|
690 |
+ ) |
|
695 | 691 |
) |
696 | 692 |
dirs_to_check: dict[str, list[str]] = {} |
697 | 693 |
json_payload: Any |
698 |
- logger.info('Assembling config structure') |
|
694 |
+ logger.info( |
|
695 |
+ _msg.TranslatedString(_msg.InfoMsgTemplate.ASSEMBLING_CONFIG_STRUCTURE) |
|
696 |
+ ) |
|
699 | 697 |
for path, json_content in sorted(json_contents.items()): |
700 | 698 |
if path.endswith('/'): |
701 | 699 |
logger.debug( |
702 |
- 'Postponing dir check: %s -> %s', |
|
703 |
- path, |
|
704 |
- json_content.decode('utf-8'), |
|
700 |
+ _msg.TranslatedString( |
|
701 |
+ _msg.DebugMsgTemplate.POSTPONING_DIRECTORY_CONTENTS_CHECK, |
|
702 |
+ path=path, |
|
703 |
+ contents=json_content.decode('utf-8'), |
|
704 |
+ ) |
|
705 | 705 |
) |
706 | 706 |
json_payload = json.loads(json_content) |
707 | 707 |
if not isinstance(json_payload, list) or any( |
... | ... |
@@ -714,17 +714,26 @@ def export_storeroom_data( # noqa: C901,PLR0912,PLR0914,PLR0915 |
714 | 714 |
raise RuntimeError(msg) |
715 | 715 |
dirs_to_check[path] = json_payload |
716 | 716 |
logger.debug( |
717 |
- 'Setting contents (empty directory): %s -> %s', path, '{}' |
|
717 |
+ _msg.TranslatedString( |
|
718 |
+ _msg.DebugMsgTemplate.SETTING_CONFIG_STRUCTURE_CONTENTS_EMPTY_DIRECTORY, |
|
719 |
+ path=path, |
|
720 |
+ ), |
|
718 | 721 |
) |
719 | 722 |
_store(config_structure, path, b'{}') |
720 | 723 |
else: |
721 | 724 |
logger.debug( |
722 |
- 'Setting contents: %s -> %s', |
|
723 |
- path, |
|
724 |
- json_content.decode('utf-8'), |
|
725 |
+ _msg.TranslatedString( |
|
726 |
+ _msg.DebugMsgTemplate.SETTING_CONFIG_STRUCTURE_CONTENTS, |
|
727 |
+ path=path, |
|
728 |
+ value=json_content.decode('utf-8'), |
|
729 |
+ ), |
|
725 | 730 |
) |
726 | 731 |
_store(config_structure, path, json_content) |
727 |
- logger.info('Checking structure consistency') |
|
732 |
+ logger.info( |
|
733 |
+ _msg.TranslatedString( |
|
734 |
+ _msg.InfoMsgTemplate.CHECKING_CONFIG_STRUCTURE_CONSISTENCY, |
|
735 |
+ ) |
|
736 |
+ ) |
|
728 | 737 |
# Sorted order is important; see `maybe_obj` below. |
729 | 738 |
for _dir, namelist in sorted(dirs_to_check.items()): |
730 | 739 |
namelist = [x.rstrip('/') for x in namelist] # noqa: PLW2901 |
... | ... |
@@ -746,6 +755,13 @@ def export_storeroom_data( # noqa: C901,PLR0912,PLR0914,PLR0915 |
746 | 755 |
if set(obj.keys()) != set(namelist): |
747 | 756 |
msg = f'Object key mismatch for path {_dir!r}' |
748 | 757 |
raise RuntimeError(msg) |
758 |
+ logger.debug( |
|
759 |
+ _msg.TranslatedString( |
|
760 |
+ _msg.DebugMsgTemplate.DIRECTORY_CONTENTS_CHECK_OK, |
|
761 |
+ path=_dir, |
|
762 |
+ contents=json.dumps(namelist), |
|
763 |
+ ) |
|
764 |
+ ) |
|
749 | 765 |
return config_structure |
750 | 766 |
|
751 | 767 |
|
... | ... |
@@ -30,6 +30,7 @@ import logging |
30 | 30 |
import warnings |
31 | 31 |
from typing import TYPE_CHECKING |
32 | 32 |
|
33 |
+from derivepassphrase import _cli_msg as _msg |
|
33 | 34 |
from derivepassphrase import exporter, vault |
34 | 35 |
|
35 | 36 |
if TYPE_CHECKING: |
... | ... |
@@ -80,8 +81,8 @@ __all__ = ('export_vault_native_data',) |
80 | 81 |
logger = logging.getLogger(__name__) |
81 | 82 |
|
82 | 83 |
|
83 |
-def _h(bs: bytes | bytearray) -> str: |
|
84 |
- return 'bytes.fromhex({!r})'.format(bs.hex(' ')) |
|
84 |
+def _h(bs: Buffer) -> str: |
|
85 |
+ return '<{}>'.format(memoryview(bs).hex(' ')) |
|
85 | 86 |
|
86 | 87 |
|
87 | 88 |
class VaultNativeConfigParser(abc.ABC): |
... | ... |
@@ -174,19 +175,25 @@ class VaultNativeConfigParser(abc.ABC): |
174 | 175 |
).derive(bytes(password)) |
175 | 176 |
result_key = raw_key.hex().lower().encode('ASCII') |
176 | 177 |
logger.debug( |
177 |
- 'binary = pbkdf2(%s, %s, %s, %s, %s) = %s -> %s', |
|
178 |
- repr(password), |
|
179 |
- repr(vault.Vault._UUID), # noqa: SLF001 |
|
180 |
- iterations, |
|
181 |
- key_size // 2, |
|
182 |
- repr('sha1'), |
|
183 |
- _h(raw_key), |
|
184 |
- _h(result_key), |
|
178 |
+ _msg.TranslatedString( |
|
179 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_PBKDF2_CALL, |
|
180 |
+ password=password, |
|
181 |
+ salt=vault.Vault._UUID, # noqa: SLF001 |
|
182 |
+ iterations=iterations, |
|
183 |
+ key_size=key_size // 2, |
|
184 |
+ algorithm='sha1', |
|
185 |
+ raw_result=raw_key, |
|
186 |
+ result_key=result_key.decode('ASCII'), |
|
187 |
+ ), |
|
185 | 188 |
) |
186 | 189 |
return result_key |
187 | 190 |
|
188 | 191 |
def _parse_contents(self) -> None: |
189 |
- logger.info('Parsing IV, payload and signature from the file contents') |
|
192 |
+ logger.info( |
|
193 |
+ _msg.TranslatedString( |
|
194 |
+ _msg.InfoMsgTemplate.VAULT_NATIVE_PARSING_IV_PAYLOAD_MAC, |
|
195 |
+ ), |
|
196 |
+ ) |
|
190 | 197 |
|
191 | 198 |
if len(self._contents) < self._iv_size + 16 + self._mac_size: |
192 | 199 |
msg = 'Invalid vault configuration file: file is truncated' |
... | ... |
@@ -202,15 +209,21 @@ class VaultNativeConfigParser(abc.ABC): |
202 | 209 |
self._iv, self._payload = cut(self._message, cutpos2) |
203 | 210 |
|
204 | 211 |
logger.debug( |
205 |
- 'buffer %s = [[%s, %s], %s]', |
|
206 |
- _h(self._contents), |
|
207 |
- _h(self._iv), |
|
208 |
- _h(self._payload), |
|
209 |
- _h(self._message_tag), |
|
212 |
+ _msg.TranslatedString( |
|
213 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_PARSE_BUFFER, |
|
214 |
+ contents=_h(self._contents), |
|
215 |
+ iv=_h(self._iv), |
|
216 |
+ payload=_h(self._payload), |
|
217 |
+ mac=_h(self._message_tag), |
|
218 |
+ ), |
|
210 | 219 |
) |
211 | 220 |
|
212 | 221 |
def _derive_keys(self) -> None: |
213 |
- logger.info('Deriving an encryption and signing key') |
|
222 |
+ logger.info( |
|
223 |
+ _msg.TranslatedString( |
|
224 |
+ _msg.InfoMsgTemplate.VAULT_NATIVE_DERIVING_KEYS, |
|
225 |
+ ), |
|
226 |
+ ) |
|
214 | 227 |
self._generate_keys() |
215 | 228 |
assert len(self._encryption_key) == self._encryption_key_size, ( |
216 | 229 |
'Derived encryption key is invalid' |
... | ... |
@@ -224,13 +237,19 @@ class VaultNativeConfigParser(abc.ABC): |
224 | 237 |
raise AssertionError |
225 | 238 |
|
226 | 239 |
def _check_signature(self) -> None: |
227 |
- logger.info('Checking HMAC signature') |
|
240 |
+ logger.info( |
|
241 |
+ _msg.TranslatedString( |
|
242 |
+ _msg.InfoMsgTemplate.VAULT_NATIVE_CHECKING_MAC, |
|
243 |
+ ), |
|
244 |
+ ) |
|
228 | 245 |
mac = hmac.HMAC(self._signing_key, hashes.SHA256()) |
229 | 246 |
mac_input = self._hmac_input() |
230 | 247 |
logger.debug( |
231 |
- 'mac_input = %s, expected_tag = %s', |
|
232 |
- _h(mac_input), |
|
233 |
- _h(self._message_tag), |
|
248 |
+ _msg.TranslatedString( |
|
249 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_CHECKING_MAC_DETAILS, |
|
250 |
+ mac_input=_h(mac_input), |
|
251 |
+ mac=_h(self._message_tag), |
|
252 |
+ ), |
|
234 | 253 |
) |
235 | 254 |
mac.update(mac_input) |
236 | 255 |
try: |
... | ... |
@@ -244,16 +263,31 @@ class VaultNativeConfigParser(abc.ABC): |
244 | 263 |
raise AssertionError |
245 | 264 |
|
246 | 265 |
def _decrypt_payload(self) -> Any: # noqa: ANN401 |
266 |
+ logger.info( |
|
267 |
+ _msg.TranslatedString( |
|
268 |
+ _msg.InfoMsgTemplate.VAULT_NATIVE_DECRYPTING_CONTENTS, |
|
269 |
+ ), |
|
270 |
+ ) |
|
247 | 271 |
decryptor = self._make_decryptor() |
248 | 272 |
padded_plaintext = bytearray() |
249 | 273 |
padded_plaintext.extend(decryptor.update(self._payload)) |
250 | 274 |
padded_plaintext.extend(decryptor.finalize()) |
251 |
- logger.debug('padded plaintext = %s', _h(padded_plaintext)) |
|
275 |
+ logger.debug( |
|
276 |
+ _msg.TranslatedString( |
|
277 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_PADDED_PLAINTEXT, |
|
278 |
+ contents=_h(padded_plaintext), |
|
279 |
+ ), |
|
280 |
+ ) |
|
252 | 281 |
unpadder = padding.PKCS7(self._iv_size * 8).unpadder() |
253 | 282 |
plaintext = bytearray() |
254 | 283 |
plaintext.extend(unpadder.update(padded_plaintext)) |
255 | 284 |
plaintext.extend(unpadder.finalize()) |
256 |
- logger.debug('plaintext = %s', _h(plaintext)) |
|
285 |
+ logger.debug( |
|
286 |
+ _msg.TranslatedString( |
|
287 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_PLAINTEXT, |
|
288 |
+ contents=_h(plaintext), |
|
289 |
+ ), |
|
290 |
+ ) |
|
257 | 291 |
return json.loads(plaintext) |
258 | 292 |
|
259 | 293 |
@abc.abstractmethod |
... | ... |
@@ -280,12 +314,6 @@ class VaultNativeV03ConfigParser(VaultNativeConfigParser): |
280 | 314 |
self._iv_size = 16 |
281 | 315 |
self._mac_size = 32 |
282 | 316 |
|
283 |
- def __call__(self) -> Any: # noqa: ANN401 |
|
284 |
- if self._data is self._sentinel: |
|
285 |
- logger.info('Attempting to parse as v0.3 configuration') |
|
286 |
- return super().__call__() |
|
287 |
- return self._data |
|
288 |
- |
|
289 | 317 |
def _generate_keys(self) -> None: |
290 | 318 |
self._encryption_key = self._pbkdf2(self._password, self.KEY_SIZE, 100) |
291 | 319 |
self._signing_key = self._pbkdf2(self._password, self.KEY_SIZE, 200) |
... | ... |
@@ -323,17 +351,17 @@ class VaultNativeV02ConfigParser(VaultNativeConfigParser): |
323 | 351 |
self._iv_size = 16 |
324 | 352 |
self._mac_size = 64 |
325 | 353 |
|
326 |
- def __call__(self) -> Any: # noqa: ANN401 |
|
327 |
- if self._data is self._sentinel: |
|
328 |
- logger.info('Attempting to parse as v0.2 configuration') |
|
329 |
- return super().__call__() |
|
330 |
- return self._data |
|
331 |
- |
|
332 | 354 |
def _parse_contents(self) -> None: |
333 | 355 |
super()._parse_contents() |
334 |
- logger.debug('Decoding payload (base64) and message tag (hex)') |
|
335 | 356 |
self._payload = base64.standard_b64decode(self._payload) |
336 | 357 |
self._message_tag = bytes.fromhex(self._message_tag.decode('ASCII')) |
358 |
+ logger.debug( |
|
359 |
+ _msg.TranslatedString( |
|
360 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_V02_PAYLOAD_MAC_POSTPROCESSING, |
|
361 |
+ payload=_h(self._payload), |
|
362 |
+ mac=_h(self._message_tag), |
|
363 |
+ ), |
|
364 |
+ ) |
|
337 | 365 |
|
338 | 366 |
def _generate_keys(self) -> None: |
339 | 367 |
self._encryption_key = self._pbkdf2(self._password, 8, 16) |
... | ... |
@@ -353,16 +381,15 @@ class VaultNativeV02ConfigParser(VaultNativeConfigParser): |
353 | 381 |
last_block = b'' |
354 | 382 |
salt = b'' |
355 | 383 |
logger.debug( |
356 |
- ( |
|
357 |
- 'data = %s, salt = %s, key_size = %s, iv_size = %s, ' |
|
358 |
- 'buffer length = %s, buffer = %s' |
|
384 |
+ _msg.TranslatedString( |
|
385 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_EVP_BYTESTOKEY_INIT, |
|
386 |
+ data=_h(data), |
|
387 |
+ salt=_h(salt), |
|
388 |
+ key_size=key_size, |
|
389 |
+ iv_size=iv_size, |
|
390 |
+ buffer_length=len(buffer), |
|
391 |
+ buffer=_h(buffer), |
|
359 | 392 |
), |
360 |
- _h(data), |
|
361 |
- _h(salt), |
|
362 |
- key_size, |
|
363 |
- iv_size, |
|
364 |
- len(buffer), |
|
365 |
- _h(buffer), |
|
366 | 393 |
) |
367 | 394 |
while len(buffer) < total_size: |
368 | 395 |
with warnings.catch_warnings(): |
... | ... |
@@ -376,12 +403,18 @@ class VaultNativeV02ConfigParser(VaultNativeConfigParser): |
376 | 403 |
last_block = block.finalize() |
377 | 404 |
buffer.extend(last_block) |
378 | 405 |
logger.debug( |
379 |
- 'buffer length = %s, buffer = %s', len(buffer), _h(buffer) |
|
406 |
+ _msg.TranslatedString( |
|
407 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_EVP_BYTESTOKEY_ROUND, |
|
408 |
+ buffer_length=len(buffer), |
|
409 |
+ buffer=_h(buffer), |
|
410 |
+ ), |
|
380 | 411 |
) |
381 | 412 |
logger.debug( |
382 |
- 'encryption_key = %s, iv = %s', |
|
383 |
- _h(buffer[:key_size]), |
|
384 |
- _h(buffer[key_size:total_size]), |
|
413 |
+ _msg.TranslatedString( |
|
414 |
+ _msg.DebugMsgTemplate.VAULT_NATIVE_EVP_BYTESTOKEY_RESULT, |
|
415 |
+ enc_key=_h(buffer[:key_size]), |
|
416 |
+ iv=_h(buffer[key_size:total_size]), |
|
417 |
+ ), |
|
385 | 418 |
) |
386 | 419 |
return bytes(buffer[:key_size]), bytes(buffer[key_size:total_size]) |
387 | 420 |
|
388 | 421 |