mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 05:28:59 +01:00 
			
		
		
		
	verifying password with hash on the backend to make sure we don't decrypt garbage and also to make sure that everything is encrypted with same password/key
This commit is contained in:
		
							parent
							
								
									53d327e435
								
							
						
					
					
						commit
						87c1a95ccc
					
				@ -2,7 +2,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import getpass
 | 
					import getpass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt  # pip install bcrypt
 | 
					import scrypt  # pip install scrypt
 | 
				
			||||||
 | 
					import binascii
 | 
				
			||||||
 | 
					
 | 
				
			||||||
password1 = getpass.getpass()
 | 
					password1 = getpass.getpass()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -11,9 +12,17 @@ print('Repeat the same password:')
 | 
				
			|||||||
password2 = getpass.getpass()
 | 
					password2 = getpass.getpass()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if password1 == password2:
 | 
					if password1 == password2:
 | 
				
			||||||
    salt = bcrypt.gensalt()
 | 
					    # salt is constant
 | 
				
			||||||
 | 
					    salt = "dc73b57736511340f132e4b5521d178afa6311c45e0c25e6a9339038507852a6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print('Generated hash:')
 | 
					    hashed = scrypt.hash(password=password1,
 | 
				
			||||||
    print(bcrypt.hashpw(password1, salt))
 | 
					                           salt=salt,
 | 
				
			||||||
 | 
					                           N=16384,
 | 
				
			||||||
 | 
					                           r=16,
 | 
				
			||||||
 | 
					                           p=1,
 | 
				
			||||||
 | 
					                           buflen=32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print('Generated password hash:')
 | 
				
			||||||
 | 
					    print(binascii.hexlify(hashed))
 | 
				
			||||||
else:
 | 
					else:
 | 
				
			||||||
    print('Entered passwords are not identical!')
 | 
					    print('Entered passwords are not identical!')
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/app.py
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/app.py
									
									
									
									
									
								
							@ -1,6 +1,7 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bcrypt
 | 
					import binascii
 | 
				
			||||||
 | 
					import scrypt
 | 
				
			||||||
import configparser
 | 
					import configparser
 | 
				
			||||||
from flask import Flask, request, send_from_directory
 | 
					from flask import Flask, request, send_from_directory
 | 
				
			||||||
from flask import render_template, redirect
 | 
					from flask import render_template, redirect
 | 
				
			||||||
@ -11,6 +12,7 @@ from notes_api import notes_api
 | 
				
			|||||||
from sql import connect
 | 
					from sql import connect
 | 
				
			||||||
from tree_api import tree_api
 | 
					from tree_api import tree_api
 | 
				
			||||||
from notes_move_api import notes_move_api
 | 
					from notes_move_api import notes_move_api
 | 
				
			||||||
 | 
					from password_api import password_api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config = configparser.ConfigParser()
 | 
					config = configparser.ConfigParser()
 | 
				
			||||||
config.read('config.ini')
 | 
					config.read('config.ini')
 | 
				
			||||||
@ -20,6 +22,7 @@ app.secret_key = config['Security']['flaskSecretKey']
 | 
				
			|||||||
app.register_blueprint(tree_api)
 | 
					app.register_blueprint(tree_api)
 | 
				
			||||||
app.register_blueprint(notes_api)
 | 
					app.register_blueprint(notes_api)
 | 
				
			||||||
app.register_blueprint(notes_move_api)
 | 
					app.register_blueprint(notes_move_api)
 | 
				
			||||||
 | 
					app.register_blueprint(password_api)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class User(UserMixin):
 | 
					class User(UserMixin):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
@ -53,11 +56,26 @@ connect(documentPath)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
hashedPassword = config['Login']['password-hash'].encode('utf-8')
 | 
					hashedPassword = config['Login']['password-hash'].encode('utf-8')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def verify_password(hex_hashed_password, guessed_password):
 | 
				
			||||||
 | 
					    hashed_password = binascii.unhexlify(hex_hashed_password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    salt = "dc73b57736511340f132e4b5521d178afa6311c45e0c25e6a9339038507852a6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hashed = scrypt.hash(password=guessed_password,
 | 
				
			||||||
 | 
					                         salt=salt,
 | 
				
			||||||
 | 
					                         N=16384,
 | 
				
			||||||
 | 
					                         r=16,
 | 
				
			||||||
 | 
					                         p=1,
 | 
				
			||||||
 | 
					                         buflen=32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return hashed == hashed_password
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route('/login', methods=['POST'])
 | 
					@app.route('/login', methods=['POST'])
 | 
				
			||||||
def login_post():
 | 
					def login_post():
 | 
				
			||||||
    inputPassword = request.form['password'].encode('utf-8')
 | 
					    inputPassword = request.form['password'].encode('utf-8')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if request.form['username'] == user.id and bcrypt.hashpw(inputPassword, hashedPassword) == hashedPassword:
 | 
					    if request.form['username'] == user.id and verify_password(hashedPassword, inputPassword):
 | 
				
			||||||
        rememberMe = True if 'remember-me' in request.form else False
 | 
					        rememberMe = True if 'remember-me' in request.form else False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        login_user(user, remember=rememberMe)
 | 
					        login_user(user, remember=rememberMe)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								src/password_api.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/password_api.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					from flask import Blueprint, jsonify, request
 | 
				
			||||||
 | 
					from flask_login import login_required
 | 
				
			||||||
 | 
					import hashlib
 | 
				
			||||||
 | 
					import configparser
 | 
				
			||||||
 | 
					import binascii
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					password_api = Blueprint('password_api', __name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@password_api.route('/password/verify', methods = ['POST'])
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def verifyPassword():
 | 
				
			||||||
 | 
					    req = request.get_json(force=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config = configparser.ConfigParser()
 | 
				
			||||||
 | 
					    config.read('config.ini')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hashedPassword = config['Login']['password-hash'].encode('utf-8')
 | 
				
			||||||
 | 
					    hashedPasswordBytes = binascii.unhexlify(hashedPassword)
 | 
				
			||||||
 | 
					    hashedPasswordSha = hashlib.sha256(hashedPasswordBytes).hexdigest()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print(req['password'])
 | 
				
			||||||
 | 
					    print(hashedPasswordSha)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    isValid = req['password'] == hashedPasswordSha
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return jsonify({
 | 
				
			||||||
 | 
					        'valid': isValid
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
@ -204,9 +204,7 @@ function addRecentNote(noteTreeId, noteContentId) {
 | 
				
			|||||||
function deriveEncryptionKey(password) {
 | 
					function deriveEncryptionKey(password) {
 | 
				
			||||||
    // why this is done is explained here: https://github.com/ricmoo/scrypt-js - "Encoding notes"
 | 
					    // why this is done is explained here: https://github.com/ricmoo/scrypt-js - "Encoding notes"
 | 
				
			||||||
    const normalizedPassword = password.normalize('NFKC');
 | 
					    const normalizedPassword = password.normalize('NFKC');
 | 
				
			||||||
    // use password as a base for salt (which is itself salted with constant) so that we don't need to store it
 | 
					    const salt = "dc73b57736511340f132e4b5521d178afa6311c45e0c25e6a9339038507852a6";
 | 
				
			||||||
    // this means everything is encrypted with the same salt.
 | 
					 | 
				
			||||||
    const salt = sha256("Jg&)hZ$" + normalizedPassword + "*P7j.");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const passwordBuffer = new buffer.SlowBuffer(normalizedPassword);
 | 
					    const passwordBuffer = new buffer.SlowBuffer(normalizedPassword);
 | 
				
			||||||
    const saltBuffer = new buffer.SlowBuffer(salt);
 | 
					    const saltBuffer = new buffer.SlowBuffer(salt);
 | 
				
			||||||
@ -228,8 +226,25 @@ function deriveEncryptionKey(password) {
 | 
				
			|||||||
            else if (key) {
 | 
					            else if (key) {
 | 
				
			||||||
                console.log("Computation took " + (new Date().getTime() - startedDate.getTime()) + "ms");
 | 
					                console.log("Computation took " + (new Date().getTime() - startedDate.getTime()) + "ms");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $.ajax({
 | 
				
			||||||
 | 
					                    url: baseUrl + 'password/verify',
 | 
				
			||||||
 | 
					                    type: 'POST',
 | 
				
			||||||
 | 
					                    data: JSON.stringify({
 | 
				
			||||||
 | 
					                        password: sha256(key)
 | 
				
			||||||
 | 
					                    }),
 | 
				
			||||||
 | 
					                    contentType: "application/json",
 | 
				
			||||||
 | 
					                    success: function (result) {
 | 
				
			||||||
 | 
					                        if (result.valid) {
 | 
				
			||||||
                            resolve(key);
 | 
					                            resolve(key);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                        else {
 | 
				
			||||||
 | 
					                            alert("Wrong password");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            reject();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
                // update UI with progress complete
 | 
					                // update UI with progress complete
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user