This will do the trick. Look ahead is nice for this...
//Matches alphanumeric or specified special characters and requires at least 2 digits
/^(?=.*\d.*\d)[0-9A-Za-z!@#$%]{4,20}$/
BONUS requires one of each: uppercase, lowercase, digit, and specified special characters
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d.*\d)(?=.*[!@#$%])[0-9A-Za-z!@#$%]{4,20}$/
EXPLAINED in pieces below
Look ahead/require for a lower case:
(?=.*[a-z])
Look ahead/require an uppercase:
(?=.*[A-Z])
Look ahead/require two digit:
(?=.*\d.*\d)
Look ahead/require only specified special chars:
(?=.*[!@#$%])
Entire password must contain a minimum of 4 and maximum of 20 only alpha numeric and specified special chars:
[0-9A-Za-z!@#$%]{4,20}
Symbols allowed are : ! @ # $ % *part bothers me. Why are you only allowing certain symbols? You should allow the entire character set since you're passing the password off to a library like bcrypt anyways which will produce a hash. You ARE basing your passwords, right?$dmr, don't do that" comments.