11
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
# See the License for the specific language governing permissions and
13
13
# limitations under the License.
14
+ import argparse
14
15
import getpass
16
+ import logging
17
+ import uuid
15
18
from typing import Optional
16
19
17
20
from ccnpy .crypto .AeadKey import AeadKey , AeadGcm , AeadCcm
21
+ from ccnpy .crypto .HpkeKdfIdentifiers import HpkeKdfIdentifiers
18
22
from ccnpy .crypto .InsecureKeystore import InsecureKeystore
19
23
from ccnpy .crypto .RsaKey import RsaKey
20
24
from ccnpy .crypto .RsaSha256 import RsaSha256Signer , RsaSha256Verifier
25
+ from ccnpy .flic .RsaOaepCtx .RsaOaepEncryptor import RsaOaepEncryptor
21
26
from ccnpy .flic .aeadctx .AeadDecryptor import AeadDecryptor
22
27
from ccnpy .flic .aeadctx .AeadEncryptor import AeadEncryptor
28
+ from ccnpy .flic .aeadctx .AeadParameters import AeadParameters
29
+ from ccnpy .flic .tlvs .KdfAlg import KdfAlg
30
+ from ccnpy .flic .tlvs .KdfData import KdfData
31
+ from ccnpy .flic .tlvs .KdfInfo import KdfInfo
32
+ from ccnpy .flic .tlvs .KeyNumber import KeyNumber
23
33
24
34
35
+ logger = logging .getLogger (__name__ )
36
+
37
+
38
+ def _str_to_array (value : str ):
39
+ """
40
+ Accept a string in the forms "0xabcd..." or "abcd..." (both in hex) and output
41
+ an array['B', ...]
42
+ """
43
+ if value .startswith ('0x' ):
44
+ offset = 2
45
+ else :
46
+ offset = 0
47
+
48
+ return bytes .fromhex (value [offset :])
49
+
25
50
def add_encryption_cli_args (parser ):
26
51
27
52
parser .add_argument ('-k' , dest = "key_file" , default = None ,
28
53
help = "RSA key in PEM format to sign the root manifest" )
29
54
parser .add_argument ('-p' , dest = "key_pass" , default = None ,
30
55
help = "RSA key password (otherwise will prompt)" )
31
56
32
- parser .add_argument ('--enc-key' , dest = "enc_key" , default = None , help = "AES encryption key (hex string)" )
33
- parser .add_argument ("--aes-mode" , dest = "aes_mode" , default = 'GCM' , choices = ['GCM' , 'CCM' ], help = "Encryption algorithm, default GCM" )
34
- parser .add_argument ('--key-num' , dest = "key_num" , type = int , default = None ,
57
+ parser .add_argument ('--wrap-key' , dest = "wrap_key" , default = None , help = "Wrapping key for RSA-OAEP mode." )
58
+ parser .add_argument ('--wrap-pass' , dest = "wrap_pass" , default = None , help = "Wrapping key key password (otherwise will prompt)." )
59
+
60
+ parser .add_argument ('--enc-key' , dest = "enc_key" ,
61
+ type = _str_to_array ,
62
+ default = None , help = "AES encryption key (hex string)" )
63
+ parser .add_argument ("--aes-mode" , dest = "aes_mode" , default = 'GCM' ,
64
+ type = lambda x : x .upper (),
65
+ choices = ['GCM' , 'CCM' ], help = "Encryption algorithm, default GCM" )
66
+ parser .add_argument ('--key-num' , dest = "key_num" , type = KeyNumber , default = None ,
35
67
help = "Key number of pre-shared key (defaults to key hash)" )
36
68
parser .add_argument ('--salt' , dest = "salt" , type = lambda x : int (x ,0 ), default = None ,
37
69
help = "Upto a 4-byte salt to include in the IV with the nonce." )
38
70
71
+ parser .add_argument ('--kdf' , dest = "kdf_alg" , type = lambda x : HpkeKdfIdentifiers .parse (x ),
72
+ choices = [HpkeKdfIdentifiers .HKDF_SHA256 , HpkeKdfIdentifiers .HKDF_SHA384 , HpkeKdfIdentifiers .HKDF_SHA512 ],
73
+ default = None ,
74
+ help = "Use a KDF" )
75
+ parser .add_argument ('--kdf-info' , dest = "kdf_info" , type = lambda x : KdfInfo (x ),
76
+ default = None ,
77
+ help = "KDF INFO string (ascii or 0x hex string)" )
78
+ parser .add_argument ('--kdf-uuid' , dest = "kdf_uuid" , default = False , action = argparse .BooleanOptionalAction ,
79
+ help = "Use a Type 1 UUID for the KdfInfo (overrides --kdf-info)" )
80
+ parser .add_argument ('--kdf-salt' , dest = "kdf_salt" , type = lambda x : int (x ,0 ), default = None ,
81
+ help = "Upto a 4-byte salt to include in the KDF function (do not use with RSA-OAEP)." )
82
+
83
+
39
84
def aes_key_from_cli_args (args ) -> Optional [AeadKey ]:
40
85
if args .enc_key is None :
41
86
return None
42
87
43
- key_bytes = bytearray .fromhex (args .enc_key )
44
88
if args .aes_mode == 'GCM' :
45
- return AeadGcm (key = key_bytes )
89
+ return AeadGcm (key = args . enc_key )
46
90
elif args .aes_mode == 'CCM' :
47
- return AeadCcm (key = key_bytes )
91
+ return AeadCcm (key = args . enc_key )
48
92
else :
49
93
raise ValueError (f'aes_mode must be GCM or CCM, got { args .aes_mode } .' )
50
94
51
- def aead_encryptor_from_cli_args (args ):
95
+ def kdf_data_from_cli (args ) -> Optional [KdfData ]:
96
+ if args .kdf_uuid :
97
+ args .kdf_info = KdfInfo (uuid .uuid1 ())
98
+
99
+ if args .kdf_alg is not None :
100
+ return KdfData (KdfAlg (args .kdf_alg ), args .kdf_info )
101
+ else :
102
+ return None
103
+
104
+ def aead_parameters_from_cli (args ):
105
+ key = aes_key_from_cli_args (args )
106
+ params = AeadParameters (
107
+ key = key ,
108
+ key_number = args .key_num ,
109
+ aead_salt = args .salt ,
110
+ kdf_data = kdf_data_from_cli (args ),
111
+ kdf_salt = args .kdf_salt )
112
+
113
+ logger .debug (params )
114
+
115
+ return params
116
+
117
+ def aead_encryptor_from_cli_args (args ) -> Optional [AeadEncryptor ]:
52
118
if args .enc_key is not None :
53
- key = aes_key_from_cli_args (args )
54
- return AeadEncryptor (key = key , key_number = args .key_num , salt = args .salt )
119
+ return AeadEncryptor (aead_parameters_from_cli (args ))
55
120
return None
56
121
57
- def aead_decryptor_from_cli_args (args ):
122
+ def aead_decryptor_from_cli_args (args ) -> Optional [ AeadDecryptor ] :
58
123
if args .enc_key is not None :
59
- key = aes_key_from_cli_args (args )
60
- return AeadDecryptor (key = key , key_number = args .key_num , salt = args .salt )
124
+ return AeadDecryptor (aead_parameters_from_cli (args ))
61
125
return None
62
126
127
+ def rsa_oaep_encryptor_from_cli_args (args ):
128
+ if args .wrap_key is None :
129
+ raise ValueError ("You must specify a wrapping key for RSA-OAEP mode." )
130
+
131
+ wrapping_key = RsaKey .load_pem_key (args .wrap_key , args .wrap_pass )
132
+ if args .enc_key is None :
133
+ encryptor = RsaOaepEncryptor .create_with_new_content_key (wrapping_key = wrapping_key , kdf_data = kdf_data_from_cli (args ))
134
+ else :
135
+ encryptor = RsaOaepEncryptor (wrapping_key = wrapping_key , params = aead_parameters_from_cli (args ))
136
+ logger .debug (encryptor )
137
+ return encryptor
138
+
139
+ def encryptor_from_cli_args (args ):
140
+ if args .wrap_key is None :
141
+ return aead_encryptor_from_cli_args (args )
142
+ else :
143
+ return rsa_oaep_encryptor_from_cli_args (args )
144
+
63
145
def rsa_signer_from_cli_args (args ):
64
146
if args .key_file is not None :
65
147
signing_key = RsaKey .load_pem_key (args .key_file , args .key_pass )
@@ -75,20 +157,26 @@ def rsa_verifier_from_cli_args(args):
75
157
def fixup_key_password (args , ask_for_pass : bool = True ):
76
158
if args .key_pass is None :
77
159
if ask_for_pass :
78
- args .key_pass = getpass .getpass (prompt = "Private key password" )
79
- else :
80
- return
160
+ args .key_pass = getpass .getpass (prompt = "Signing private key password" )
161
+ if len ( args . key_pass ) == 0 :
162
+ args . key_pass = None
81
163
82
- if len (args .key_pass ) == 0 :
83
- args .key_pass = None
164
+ if args .wrap_key is not None and args .wrap_pass is None :
165
+ if ask_for_pass :
166
+ args .wrap_pass = getpass .getpass (prompt = "Wrapping key password" )
167
+ if len (args .wrap_pass ) == 0 :
168
+ args .wrap_pass = None
84
169
85
170
def create_keystore (args ):
86
171
keystore = InsecureKeystore ()
87
- aes_key = aes_key_from_cli_args (args )
88
- if aes_key is not None :
89
- keystore .add_aes_key (args . key_num , aes_key , args . salt )
172
+ aead_params = aead_parameters_from_cli (args )
173
+ if aead_params . key is not None :
174
+ keystore .add_aes_key (aead_params )
90
175
91
176
if args .key_file is not None :
92
177
keystore .add_rsa_key (name = 'default' , key = RsaKey .load_pem_key (args .key_file , args .key_pass ))
93
178
179
+ if args .wrap_key is not None :
180
+ keystore .add_rsa_key (name = 'wrap' , key = RsaKey .load_pem_key (args .wrap_key , args .wrap_pass ))
181
+
94
182
return keystore
0 commit comments