import com.gitblit.Constants.RegistrantType;\r
import com.gitblit.utils.ArrayUtils;\r
import com.gitblit.utils.ModelUtils;\r
+import com.gitblit.utils.SecureRandom;\r
import com.gitblit.utils.StringUtils;\r
\r
/**\r
\r
public static final UserModel ANONYMOUS = new UserModel();\r
\r
+ private static final SecureRandom RANDOM = new SecureRandom();\r
+\r
// field names are reflectively mapped in EditUser page\r
public String username;\r
public String password;\r
String projectPath = StringUtils.getFirstPathElement(repository);\r
return !StringUtils.isEmpty(projectPath) && projectPath.equalsIgnoreCase(getPersonalPath());\r
}\r
- \r
+\r
public String createCookie() {\r
- SecureRandom random = new SecureRandom();\r
- byte[] values = new byte[20];\r
- random.nextBytes(values);\r
- return StringUtils.getSHA1(String.valueOf(values));\r
+ return StringUtils.getSHA1(RANDOM.randomBytes(32));\r
}\r
}\r
--- /dev/null
+/*
+ * Copyright 2016 gitblit.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.utils;
+
+/**
+ * Wrapper class for java.security.SecureRandom, which will periodically reseed
+ * the PRNG in case an instance of the class has been running for a long time.
+ *
+ * @author Florian Zschocke
+ */
+public class SecureRandom {
+
+ /** Period (in ms) after which a new SecureRandom will be created in order to get a fresh random seed. */
+ private static final long RESEED_PERIOD = 24 * 60 * 60 * 1000; /* 24 hours */
+
+
+ private long last;
+ private java.security.SecureRandom random;
+
+
+
+ public SecureRandom() {
+ // Make sure the SecureRandom is seeded right from the start.
+ // This also lets any blocks during seeding occur at creation
+ // and prevents it from happening when getting next random bytes.
+ seed();
+ }
+
+
+
+ public byte[] randomBytes(int num) {
+ byte[] bytes = new byte[num];
+ nextBytes(bytes);
+ return bytes;
+ }
+
+
+ public void nextBytes(byte[] bytes) {
+ random.nextBytes(bytes);
+ reseed(false);
+ }
+
+
+ void reseed(boolean forced) {
+ long ts = System.currentTimeMillis();
+ if (forced || (ts - last) > RESEED_PERIOD) {
+ last = ts;
+ runReseed();
+ }
+ }
+
+
+
+ private void seed() {
+ random = new java.security.SecureRandom();
+ random.nextBytes(new byte[0]);
+ last = System.currentTimeMillis();
+ }
+
+
+ private void runReseed() {
+ // Have some other thread hit the penalty potentially incurred by reseeding,
+ // so that we can immediately return and not block the operation in progress.
+ new Thread() {
+ public void run() {
+ seed();
+ }
+ }.start();
+ }
+}
--- /dev/null
+package com.gitblit.utils;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+public class SecureRandomTest {
+
+ @Test
+ public void testRandomBytes() {
+ SecureRandom sr = new SecureRandom();
+ byte[] bytes1 = sr.randomBytes(10);
+ assertEquals(10, bytes1.length);
+ byte[] bytes2 = sr.randomBytes(10);
+ assertEquals(10, bytes2.length);
+ assertFalse(Arrays.equals(bytes1, bytes2));
+
+ assertEquals(0, sr.randomBytes(0).length);
+ assertEquals(200, sr.randomBytes(200).length);
+ }
+
+ @Test
+ public void testNextBytes() {
+ SecureRandom sr = new SecureRandom();
+ byte[] bytes1 = new byte[32];
+ sr.nextBytes(bytes1);
+ byte[] bytes2 = new byte[32];
+ sr.nextBytes(bytes2);
+ assertFalse(Arrays.equals(bytes1, bytes2));
+ }
+}