Beispiel #1
0
 def upload_file(cls, user, data):
     from hashlib import sha512
     from config import allowed_file_suffix_list
     filename = data.filename
     assert len(filename) <= 64, 'filename too long (>64B)'
     assert filename_pattern.fullmatch(filename), 'no unicode character allowed'
     filename_suffix = filename.rsplit('.', maxsplit=1)[-1]
     assert filename_suffix in allowed_file_suffix_list, 'banned file type'
     f = File.query.filter(and_(File.creator_id == user.id_, File.filename == filename)).first()
     assert not f, 'file already exists'
     content = data.read()
     assert len(content) < 1*1024*1024, 'file too large (>=10MB)'
     user_id = str(user.id_)+'/'
     if not path.exists(storage_path+user_id):
         if not path.exists(storage_path):
             mkdir(storage_path)
         mkdir(storage_path+user_id)
     # 计算原文件的哈希
     hash_value = sha512(content).hexdigest()
     # 判断文件是否存在
     if not path.exists(storage_path+user_id+hash_value):
         # 加密并存储。加密前得先还原出对称密钥。
         content = secret.symmetric_encrypt(secret.decrypt(user.encrypted_symmetric_key), content)
         # 同时计算签名
         signature = secret.sign(content)
         # 保存密文与签名
         with open(storage_path+user_id+hash_value, 'wb') as f:
             f.write(content)
         with open(storage_path+user_id+hash_value+'.sig', 'wb') as f:
             f.write(signature)
     creator_id = user.id_
     file = File(creator_id=creator_id, filename=filename, hash_value=hash_value)
     db.session.add(file)
     db.session.commit()
Beispiel #2
0
    def create_user(cls, mail, name, password, hashword):
        import secret
        from hashlib import sha256, md5

        user = User.get_by(mail=mail)
        assert user is None, '填写的注册邮箱已存在'
        token = md5(("%s%s" % (name, mail)).encode('utf-8')).hexdigest()
        authcode = User.generate_verify_authcode()
        assert User.send_verify_email(name, mail, token, authcode).status_code == 200, \
         "验证邮件发送失败"

        # 随机生成一个用户的对称密钥与公私钥
        symmetric_key = secret.new_symmetric_key()
        private_key, public_key = secret.new_pair()
        # 用用户的密码对用户的私钥加密(对称加密)
        digest = sha256(password.encode('utf-8')).hexdigest()
        encrypted_prikey = secret.symmetric_encrypt(bytes.fromhex(digest),
                                                    private_key)
        # 对对称密钥加密
        encrypted_symkey = secret.encrypt(private_key, symmetric_key)
        user = User(usrname=name,
                    hashword=hashword,
                    mail=mail,
                    token=token,
                    authcode=authcode,
                    symkey=encrypted_symkey,
                    privkey=encrypted_prikey,
                    pubkey=public_key)
        db.session.add(user)
        db.session.commit()
Beispiel #3
0
    def decrypt_and_encrypt(cls, fid, user, sym_key):
        from .file import File
        from .online_user import OnlineUser
        import secret

        # 获取私钥解密获得对称密钥
        usr = OnlineUser.query.filter(OnlineUser.usrid == user.usrid).first()
        Pk = usr.Pk
        enc_key = secret.decrypt(Pk, user.symkey)
        # 查询、读取本地存储的加密文件
        f = File.get_by(fileid = fid)
        hash_value = f.sha256
        with open(storage_path + str(user.usrid) + '/' + hash_value, 'rb') as f:
            content = f.read()

        # 解密文件
        content = secret.symmetric_decrypt(enc_key, content)
        # 用私钥签名
        sig = secret.sign(Pk, content)
        # 用新的会话密钥加密文件
        new_content = secret.symmetric_encrypt(sym_key, content)
        # 写入 shared_path
        user_id = str(user.usrid) + '/'
        head = shared_path + user_id
        full_path = head + hash_value
        if not path.exists(head):
            if not path.exists(shared_path):
                mkdir(shared_path)
            mkdir(head)

        # 判断文件是否存在
        # 分享文件夹要写入签名
        if not path.exists(full_path):
            with open(full_path, 'wb') as f:
                f.write(new_content)
            with open(full_path + '.sig', 'wb') as f:
                f.write(sig)
Beispiel #4
0
    def upload_file(cls, user, data):
        from hashlib import sha256
        from config import allowed_file_list

        filename = data.filename
        assert len(filename) <= 64, '文件名过长(>64B)'
        assert filename_pattern.fullmatch(filename), '文件名中不能包含以下字符:\n\\ / : * ? " < > |'
        mime_type = data.mimetype
        assert mime_type in allowed_file_list, '不支持的文件类型'

        content = data.read()
        hash_value = sha256(content).hexdigest()
        f = File.query.filter(and_(File.uid == user.usrid, File.sha256 == hash_value)).first()
        assert not f, '文件已存在'
        size = convert_bytes(len(content))
        assert len(content) < 20*1024*1024, '文件过大(>=20MB)'
        userid = str(user.usrid) + '/'
        hash_value = sha256(content).hexdigest()
        head = storage_path + userid
        if not path.exists(head):
            if not path.exists(storage_path):
                mkdir(storage_path)
            mkdir(head)
        if not path.exists(head + hash_value):
            # 还原对称密钥
            Pkv = OnlineUser.get_by(usrid = userid).Pk
            encrypted_symkey = User.get_by(usrid = userid).symkey
            symkey = secret.decrypt(Pkv, encrypted_symkey)
            # 加密
            content = secret.symmetric_encrypt(symkey, content)
            # 只保存密文
            with open(head + hash_value, 'wb') as f:
                f.write(content)
        fi = File(uid=user.usrid, filename=filename, size=size, sha256=hash_value)
        db.session.add(fi)
        db.session.commit()
Beispiel #5
0
def post_share():
    import random, string
    from config import domain_name, sy_public_key

    user = current_user
    fid = request.form['fid']
    choice = request.form['choice']
    nonce = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(8))
    ShareKey = secret.new_symmetric_key()
    sym_key = secret.new_symmetric_key()
    # 先对称解密再用新的分享密钥对称加密
    Share.decrypt_and_encrypt(fid, user, sym_key)
    # 分享码对对称密钥加密
    enc_key = secret.symmetric_encrypt(ShareKey, sym_key)
    # 慢速哈希分享码
    hashShareKey = argon2.using(rounds=256, memory_cost=1024).hash(ShareKey)
    # 使用服务器公钥加密分享码
    enc_ShareKey = secret.encrypt(bytes.fromhex(sy_public_key), ShareKey)
    sid = Share.add_share(fid, hashShareKey, enc_ShareKey, nonce, enc_key)
    # 向指定用户发送分享消息
    choice = choice.split(',')
    for u in choice:
        Message.create_msg(User.get_by(mail=u).usrid, user.usrname, sid, File.get_by(fileid=fid).filename)
    return '分享成功!'