CVE-2021-21253 (Java, published 2021-01-21T15:15Z)
Description: value: OnlineVotingSystem is an open source project hosted on GitHub. OnlineVotingSystem before version 1.1.2 hashes user passwords without a salt, which is vulnerable to dictionary attacks. Therefore there is a threat of security breach in the voting system. Without a salt, it is much easier for attackers to pre-compute the hash value using dictionary attack techniques such as rainbow tables to crack passwords. This problem is fixed and published in version 1.1.2. A long randomly generated salt is added to the password hash function to better protect passwords stored in the voting system.
Severity: MEDIUM (CVSS v3 base score: 5.3)
Weakness: CWE-916 \u2014 Use of Password Hash With Insufficient Computational Effort
The product generates a hash for a password, but it uses a scheme that does not provide a sufficient level of computational effort that would make password cracking attacks infeasible or expensive.
Repository: https://github.com/dbijaya/OnlineVotingSystem
Files changed:
src/com/bijay/onlinevotingsystem/controller/AdminLoginController.java
src/com/bijay/onlinevotingsystem/controller/SHA256.java
src/com/bijay/onlinevotingsystem/controller/VoterLoginController.java
src/com/bijay/onlinevotingsystem/dao/AdminDaoImpl.java
src/com/bijay/onlinevotingsystem/dao/VoterDaoImpl.java
Commit message: Add a salt to SHA-256 hash


Vulnerable code:
	SHA256 sha = new SHA256();
		String password = sha.getSHA(request.getParameter("pass"));
}
import java.math.BigInteger;

			// Static getInstance method is called with hashing SHA
			MessageDigest md = MessageDigest.getInstance("SHA-256");

			// digest() method called
			// to calculate message digest of an input
			// and return array of byte
			byte[] messageDigest = md.digest(password.getBytes());

			// Convert byte array into signum representation
			BigInteger no = new BigInteger(1, messageDigest);

			// Convert message digest into hex value
			String hashPass = no.toString(16);

			while (hashPass.length() < 32) {
				hashPass = "0" + hashPass;
			}
			return hashPass;
	SHA256 sha = new SHA256();
		String password = sha.getSHA(request.getParameter("pass"));
}
		String sql = "select * from admin_table where admin_name=? and password=?";
			ps.setString(2,password);
				return true;
		String sql = "select * from voter_table where voter_name=? and password=? and email=?";
			ps.setString(2, password);
			ps.setString(3, email);
				return true;

Fixed code:
		String password = request.getParameter("pass");
}
import java.security.SecureRandom;
import java.util.Base64;
	private static final String SSHA_PREFIX = "{SSHA}";
	private static final int SSHA_256_LENGTH = 32; // SHA-256 is 32 bytes long
	private static final int SALT_LENGTH = 16; // Use a 16 byte salt
			byte[] salt = getSalt();
			String cipher = getCipher(password, salt);
			
			return cipher;

	public static boolean validatePassword(String password, String cipherText) {
		boolean isValid = false;
		try {
			String cipher = cipherText.substring(SSHA_PREFIX.length());
		
			byte[] cipherBytes = Base64.getDecoder().decode(cipher.getBytes());
			byte[] salt = new byte[SALT_LENGTH];
			System.arraycopy(cipherBytes, SSHA_256_LENGTH, salt, 0, SALT_LENGTH);

			String result = getCipher(password, salt);
			//Compare the newly hashed password taking the same salt with the input hash
			isValid = result.equals(cipherText);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return isValid;
	}
	
	private static byte[] getSalt() throws NoSuchAlgorithmException {
		SecureRandom random = new SecureRandom();
		byte[] salt = new byte[SALT_LENGTH];
		random.nextBytes(salt);
		return salt;
	}

	private static String getCipher(String password, byte[] salt) throws NoSuchAlgorithmException {
		// Static getInstance method is called with hashing SHA
		MessageDigest md = MessageDigest.getInstance("SHA-256");
		md.update(salt);
	
		byte[] passBytes = password.getBytes();
		byte[] allBytes = new byte[passBytes.length + SALT_LENGTH];
		System.arraycopy(passBytes, 0, allBytes, 0, passBytes.length);
		System.arraycopy(salt, 0, allBytes, passBytes.length, SALT_LENGTH);
	
			
		byte[] cipherBytes = new byte[SSHA_256_LENGTH + SALT_LENGTH];
			
		// digest() method called
		// to calculate message digest of an input
		// and return array of byte
		byte[] messageDigest = md.digest(allBytes);
	
		System.arraycopy(messageDigest, 0, cipherBytes, 0, SSHA_256_LENGTH);
		System.arraycopy(salt, 0, cipherBytes, SSHA_256_LENGTH, SALT_LENGTH);
		
		String result = SSHA_PREFIX + Base64.getEncoder().encodeToString(cipherBytes);
		return result;
	}
		String password = request.getParameter("pass");
}
import javax.crypto.Cipher;

import com.bijay.onlinevotingsystem.controller.SHA256;
		String sql = "select * from admin_table where admin_name=?";
				String cipherText = rs.getString("password");
				return SHA256.validatePassword(password, cipherText);
import com.bijay.onlinevotingsystem.controller.SHA256;
		String sql = "select * from voter_table where voter_name=? and email=?";
			ps.setString(2, email);
				String cipherText = rs.getString("password");
				return SHA256.validatePassword(password, cipherText);