Browse Source

mmgen-tool: rewrite 'rand2file', add test

MMGen 6 years ago
parent
commit
7cc69a2725
3 changed files with 52 additions and 34 deletions
  1. 1 1
      mmgen/seed.py
  2. 34 33
      mmgen/tool.py
  3. 17 0
      test/test_py_d/ts_misc.py

+ 1 - 1
mmgen/seed.py

@@ -1042,7 +1042,7 @@ harder to find, you're advised to choose a much larger file size than this.
 					msg('File size must be an integer no less than {}'.format(min_fsize))
 
 				from mmgen.tool import MMGenToolCmd
-				MMGenToolCmd().rand2file(fn,str(fsize)) # threaded routine TODO: check safe
+				MMGenToolCmd().rand2file(fn,str(fsize))
 				check_offset = False
 			else:
 				die(1,'Exiting at user request')

+ 34 - 33
mmgen/tool.py

@@ -587,61 +587,62 @@ class MMGenToolCmdFileUtil(MMGenToolCmdBase):
 
 	def rand2file(self,outfile:str,nbytes:str,threads=4,silent=False):
 		"write 'n' bytes of random data to specified file"
-		nbytes = parse_bytespec(nbytes)
-		from Crypto import Random
-		rh = Random.new()
-		from queue import Queue
 		from threading import Thread
-		bsize = 2**20
-		roll = bsize * 4
-		if opt.outdir: outfile = make_full_path(opt.outdir,outfile)
-		f = open(outfile,'wb')
-
-		from Crypto.Cipher import AES
-		from Crypto.Util import Counter
-
-		key = get_random(32)
+		from queue import Queue
+		from cryptography.hazmat.primitives.ciphers import Cipher,algorithms,modes
+		from cryptography.hazmat.backends import default_backend
 
 		def encrypt_worker(wid):
+			ctr_init_val = os.urandom(g.aesctr_iv_len)
+			c = Cipher(algorithms.AES(key),modes.CTR(ctr_init_val),backend=default_backend())
+			encryptor = c.encryptor()
 			while True:
-				i,d = q1.get()
-				c = AES.new(key,AES.MODE_CTR,counter=Counter.new(g.aesctr_iv_len*8,initial_value=i))
-				enc_data = c.encrypt(d)
-				q2.put(enc_data)
+				q2.put(encryptor.update(q1.get()))
 				q1.task_done()
 
 		def output_worker():
 			while True:
-				data = q2.get()
-				f.write(data)
+				f.write(q2.get())
 				q2.task_done()
 
-		q1 = Queue()
+		nbytes = parse_bytespec(nbytes)
+		if opt.outdir:
+			outfile = make_full_path(opt.outdir,outfile)
+		f = open(outfile,'wb')
+
+		key = get_random(32)
+		q1,q2 = Queue(),Queue()
+
 		for i in range(max(1,threads-2)):
-			t = Thread(target=encrypt_worker,args=(i,))
+			t = Thread(target=encrypt_worker,args=[i])
 			t.daemon = True
 			t.start()
 
-		q2 = Queue()
 		t = Thread(target=output_worker)
 		t.daemon = True
 		t.start()
 
-		i = 1; rbytes = nbytes
-		while rbytes > 0:
-			d = rh.read(min(bsize,rbytes))
-			q1.put((i,d))
-			rbytes -= bsize
-			i += 1
-			if not (bsize*i) % roll:
-				msg_r('\rRead: {} bytes'.format(bsize*i))
+		blk_size = 1024 * 1024
+		for i in range(nbytes // blk_size):
+			if not i % 4:
+				msg_r('\rRead: {} bytes'.format(i * blk_size))
+			q1.put(os.urandom(blk_size))
+
+		if nbytes % blk_size:
+			q1.put(os.urandom(nbytes % blk_size))
 
-		if not silent:
-			msg('\rRead: {} bytes'.format(nbytes))
-			qmsg("\r{} bytes of random data written to file '{}'".format(nbytes,outfile))
 		q1.join()
 		q2.join()
 		f.close()
+
+		fsize = os.stat(outfile).st_size
+		if fsize != nbytes:
+			die(3,'{}: incorrect random file size (should be {})'.format(fsize,nbytes))
+
+		if not silent:
+			msg('\rRead: {} bytes'.format(nbytes))
+			qmsg("\r{} byte{} of random data written to file '{}'".format(nbytes,suf(nbytes),outfile))
+
 		return True
 
 class MMGenToolCmdWallet(MMGenToolCmdBase):

+ 17 - 0
test/test_py_d/ts_misc.py

@@ -85,11 +85,28 @@ class TestSuiteTool(TestSuiteMain,TestSuiteBase):
 	enc_infn = 'tool_encrypt.in'
 	cmd_group = (
 		('tool_find_incog_data', (9,"'mmgen-tool find_incog_data'", [[[hincog_fn],1],[[incog_id_fn],1]])),
+		('tool_rand2file',       (9,"'mmgen-tool rand2file'", [])),
 		('tool_encrypt',         (9,"'mmgen-tool encrypt' (random data)",     [])),
 		('tool_decrypt',         (9,"'mmgen-tool decrypt' (random data)", [[[enc_infn+'.mmenc'],9]])),
 		# ('tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)",  [])),
 	)
 
+	def tool_rand2file(self):
+		outfile = os.path.join(self.tmpdir,'rand2file.out')
+		from mmgen.tool import MMGenToolCmd
+		tu = MMGenToolCmd()
+		for nbytes in ('1','1023','1K','1048575','1M','1048577','123M'):
+			t = self.spawn( 'mmgen-tool',
+							['-d',self.tmpdir,'-r0','rand2file','rand2file.out',nbytes],
+							extra_desc='({} byte{})'.format(nbytes,suf(tu.bytespec(nbytes)))
+							)
+			t.expect('random data written to file')
+			t.read()
+			t.p.wait()
+			t.ok()
+		t.skip_ok = True
+		return t
+
 	def tool_encrypt(self):
 		infile = joinpath(self.tmpdir,self.enc_infn)
 		write_to_file(infile,os.urandom(1033),binary=True)