diff --git a/api/client/ps/custom_test.go b/api/client/ps/custom_test.go index d04c9597db..2e2adacda7 100644 --- a/api/client/ps/custom_test.go +++ b/api/client/ps/custom_test.go @@ -11,7 +11,7 @@ import ( ) func TestContainerContextID(t *testing.T) { - containerId := stringid.GenerateRandomID() + containerId := stringid.GenerateNonCryptoID() unix := time.Now().Unix() var ctx containerContext diff --git a/daemon/create_unix.go b/daemon/create_unix.go index 921d44eb73..124cec0a10 100644 --- a/daemon/create_unix.go +++ b/daemon/create_unix.go @@ -24,7 +24,7 @@ func createContainerPlatformSpecificSettings(container *Container, config *runco case 2: name, destination = parts[0], filepath.Clean(parts[1]) default: - name = stringid.GenerateRandomID() + name = stringid.GenerateNonCryptoID() destination = filepath.Clean(parts[0]) } // Skip volumes for which we already have something mounted on that diff --git a/daemon/daemon.go b/daemon/daemon.go index 911b47df5b..81272c846f 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -350,7 +350,7 @@ func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image. func (daemon *Daemon) generateIdAndName(name string) (string, string, error) { var ( err error - id = stringid.GenerateRandomID() + id = stringid.GenerateNonCryptoID() ) if name == "" { diff --git a/daemon/daemon_test.go b/daemon/daemon_test.go index 5e0233da79..89604f3140 100644 --- a/daemon/daemon_test.go +++ b/daemon/daemon_test.go @@ -135,7 +135,7 @@ func TestLoadWithVolume(t *testing.T) { t.Fatal(err) } - hostVolumeId := stringid.GenerateRandomID() + hostVolumeId := stringid.GenerateNonCryptoID() vfsPath := filepath.Join(tmp, "vfs", "dir", hostVolumeId) volumePath := filepath.Join(tmp, "volumes", hostVolumeId) @@ -419,7 +419,7 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) { t.Fatal(err) } - hostVolumeId := stringid.GenerateRandomID() + hostVolumeId := stringid.GenerateNonCryptoID() vfsPath := filepath.Join(tmp, "vfs", "dir", hostVolumeId) volumePath := filepath.Join(tmp, "volumes", hostVolumeId) diff --git a/daemon/exec.go b/daemon/exec.go index 41e27bc068..8b163aec49 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -155,7 +155,7 @@ func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, erro } execConfig := &execConfig{ - ID: stringid.GenerateRandomID(), + ID: stringid.GenerateNonCryptoID(), OpenStdin: config.AttachStdin, OpenStdout: config.AttachStdout, OpenStderr: config.AttachStderr, diff --git a/daemon/execdriver/windows/exec.go b/daemon/execdriver/windows/exec.go index 1de1c24614..f16908e6b9 100644 --- a/daemon/execdriver/windows/exec.go +++ b/daemon/execdriver/windows/exec.go @@ -19,7 +19,7 @@ func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo inListen, outListen, errListen *npipe.PipeListener term execdriver.Terminal err error - randomID string = stringid.GenerateRandomID() + randomID string = stringid.GenerateNonCryptoID() serverPipeFormat, clientPipeFormat string pid uint32 exitCode int32 diff --git a/graph/graph.go b/graph/graph.go index be911b0482..6312806b56 100644 --- a/graph/graph.go +++ b/graph/graph.go @@ -314,7 +314,7 @@ func (graph *Graph) TempLayerArchive(id string, sf *streamformatter.StreamFormat // mktemp creates a temporary sub-directory inside the graph's filesystem. func (graph *Graph) mktemp(id string) (string, error) { - dir := filepath.Join(graph.root, "_tmp", stringid.GenerateRandomID()) + dir := filepath.Join(graph.root, "_tmp", stringid.GenerateNonCryptoID()) if err := system.MkdirAll(dir, 0700); err != nil { return "", err } diff --git a/graph/graph_test.go b/graph/graph_test.go index d7dd591a3c..63ef7357b2 100644 --- a/graph/graph_test.go +++ b/graph/graph_test.go @@ -68,7 +68,7 @@ func TestInterruptedRegister(t *testing.T) { defer nukeGraph(graph) badArchive, w := io.Pipe() // Use a pipe reader as a fake archive which never yields data image := &image.Image{ - ID: stringid.GenerateRandomID(), + ID: stringid.GenerateNonCryptoID(), Comment: "testing", Created: time.Now(), } @@ -126,7 +126,7 @@ func TestRegister(t *testing.T) { t.Fatal(err) } image := &image.Image{ - ID: stringid.GenerateRandomID(), + ID: stringid.GenerateNonCryptoID(), Comment: "testing", Created: time.Now(), } @@ -229,19 +229,19 @@ func TestByParent(t *testing.T) { graph, _ := tempGraph(t) defer nukeGraph(graph) parentImage := &image.Image{ - ID: stringid.GenerateRandomID(), + ID: stringid.GenerateNonCryptoID(), Comment: "parent", Created: time.Now(), Parent: "", } childImage1 := &image.Image{ - ID: stringid.GenerateRandomID(), + ID: stringid.GenerateNonCryptoID(), Comment: "child1", Created: time.Now(), Parent: parentImage.ID, } childImage2 := &image.Image{ - ID: stringid.GenerateRandomID(), + ID: stringid.GenerateNonCryptoID(), Comment: "child2", Created: time.Now(), Parent: parentImage.ID, diff --git a/integration-cli/docker_cli_rename_test.go b/integration-cli/docker_cli_rename_test.go index 7a77f13eff..b436b51d25 100644 --- a/integration-cli/docker_cli_rename_test.go +++ b/integration-cli/docker_cli_rename_test.go @@ -14,7 +14,7 @@ func (s *DockerSuite) TestRenameStoppedContainer(c *check.C) { dockerCmd(c, "wait", cleanedContainerID) name, err := inspectField(cleanedContainerID, "Name") - newName := "new_name" + stringid.GenerateRandomID() + newName := "new_name" + stringid.GenerateNonCryptoID() dockerCmd(c, "rename", "first_name", newName) name, err = inspectField(cleanedContainerID, "Name") @@ -30,7 +30,7 @@ func (s *DockerSuite) TestRenameStoppedContainer(c *check.C) { func (s *DockerSuite) TestRenameRunningContainer(c *check.C) { out, _ := dockerCmd(c, "run", "--name", "first_name", "-d", "busybox", "sh") - newName := "new_name" + stringid.GenerateRandomID() + newName := "new_name" + stringid.GenerateNonCryptoID() cleanedContainerID := strings.TrimSpace(out) dockerCmd(c, "rename", "first_name", newName) @@ -46,7 +46,7 @@ func (s *DockerSuite) TestRenameRunningContainer(c *check.C) { func (s *DockerSuite) TestRenameCheckNames(c *check.C) { dockerCmd(c, "run", "--name", "first_name", "-d", "busybox", "sh") - newName := "new_name" + stringid.GenerateRandomID() + newName := "new_name" + stringid.GenerateNonCryptoID() dockerCmd(c, "rename", "first_name", newName) name, err := inspectField(newName, "Name") diff --git a/pkg/random/random.go b/pkg/random/random.go index 05b7f7fb37..865f5f391b 100644 --- a/pkg/random/random.go +++ b/pkg/random/random.go @@ -1,11 +1,19 @@ package random import ( + "io" "math/rand" "sync" "time" ) +// Rand is a global *rand.Rand instance, which initilized with NewSource() source. +var Rand = rand.New(NewSource()) + +// Reader is a global, shared instance of a pseudorandom bytes generator. +// It doesn't consume entropy. +var Reader io.Reader = &reader{rnd: Rand} + // copypaste from standard math/rand type lockedSource struct { lk sync.Mutex @@ -32,3 +40,22 @@ func NewSource() rand.Source { src: rand.NewSource(time.Now().UnixNano()), } } + +type reader struct { + rnd *rand.Rand +} + +func (r *reader) Read(b []byte) (int, error) { + i := 0 + for { + val := r.rnd.Int63() + for val > 0 { + b[i] = byte(val) + i++ + if i == len(b) { + return i, nil + } + val >>= 8 + } + } +} diff --git a/pkg/stringid/stringid.go b/pkg/stringid/stringid.go index 5a866f64af..ab1f9d4749 100644 --- a/pkg/stringid/stringid.go +++ b/pkg/stringid/stringid.go @@ -7,6 +7,8 @@ import ( "io" "regexp" "strconv" + + "github.com/docker/docker/pkg/random" ) const shortLen = 12 @@ -30,20 +32,36 @@ func TruncateID(id string) string { return id[:trimTo] } -// GenerateRandomID returns an unique id. -func GenerateRandomID() string { +func generateID(crypto bool) string { + b := make([]byte, 32) + var r io.Reader = random.Reader + if crypto { + r = rand.Reader + } for { - id := make([]byte, 32) - if _, err := io.ReadFull(rand.Reader, id); err != nil { + if _, err := io.ReadFull(r, b); err != nil { panic(err) // This shouldn't happen } - value := hex.EncodeToString(id) + id := hex.EncodeToString(b) // if we try to parse the truncated for as an int and we don't have // an error then the value is all numberic and causes issues when // used as a hostname. ref #3869 - if _, err := strconv.ParseInt(TruncateID(value), 10, 64); err == nil { + if _, err := strconv.ParseInt(TruncateID(id), 10, 64); err == nil { continue } - return value + return id } } + +// GenerateRandomID returns an unique id. +func GenerateRandomID() string { + return generateID(true) + +} + +// GenerateNonCryptoID generates unique id without using cryptographically +// secure sources of random. +// It helps you to save entropy. +func GenerateNonCryptoID() string { + return generateID(false) +} diff --git a/pkg/truncindex/truncindex_test.go b/pkg/truncindex/truncindex_test.go index cc7bc01d4c..8197baf7d4 100644 --- a/pkg/truncindex/truncindex_test.go +++ b/pkg/truncindex/truncindex_test.go @@ -134,7 +134,7 @@ func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult strin func BenchmarkTruncIndexAdd100(b *testing.B) { var testSet []string for i := 0; i < 100; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -150,7 +150,7 @@ func BenchmarkTruncIndexAdd100(b *testing.B) { func BenchmarkTruncIndexAdd250(b *testing.B) { var testSet []string for i := 0; i < 250; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -166,7 +166,7 @@ func BenchmarkTruncIndexAdd250(b *testing.B) { func BenchmarkTruncIndexAdd500(b *testing.B) { var testSet []string for i := 0; i < 500; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -183,7 +183,7 @@ func BenchmarkTruncIndexGet100(b *testing.B) { var testSet []string var testKeys []string for i := 0; i < 100; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } index := NewTruncIndex([]string{}) for _, id := range testSet { @@ -207,7 +207,7 @@ func BenchmarkTruncIndexGet250(b *testing.B) { var testSet []string var testKeys []string for i := 0; i < 250; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } index := NewTruncIndex([]string{}) for _, id := range testSet { @@ -231,7 +231,7 @@ func BenchmarkTruncIndexGet500(b *testing.B) { var testSet []string var testKeys []string for i := 0; i < 500; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } index := NewTruncIndex([]string{}) for _, id := range testSet { @@ -254,7 +254,7 @@ func BenchmarkTruncIndexGet500(b *testing.B) { func BenchmarkTruncIndexDelete100(b *testing.B) { var testSet []string for i := 0; i < 100; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -277,7 +277,7 @@ func BenchmarkTruncIndexDelete100(b *testing.B) { func BenchmarkTruncIndexDelete250(b *testing.B) { var testSet []string for i := 0; i < 250; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -300,7 +300,7 @@ func BenchmarkTruncIndexDelete250(b *testing.B) { func BenchmarkTruncIndexDelete500(b *testing.B) { var testSet []string for i := 0; i < 500; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -323,7 +323,7 @@ func BenchmarkTruncIndexDelete500(b *testing.B) { func BenchmarkTruncIndexNew100(b *testing.B) { var testSet []string for i := 0; i < 100; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -334,7 +334,7 @@ func BenchmarkTruncIndexNew100(b *testing.B) { func BenchmarkTruncIndexNew250(b *testing.B) { var testSet []string for i := 0; i < 250; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -345,7 +345,7 @@ func BenchmarkTruncIndexNew250(b *testing.B) { func BenchmarkTruncIndexNew500(b *testing.B) { var testSet []string for i := 0; i < 500; i++ { - testSet = append(testSet, stringid.GenerateRandomID()) + testSet = append(testSet, stringid.GenerateNonCryptoID()) } b.ResetTimer() for i := 0; i < b.N; i++ { @@ -357,7 +357,7 @@ func BenchmarkTruncIndexAddGet100(b *testing.B) { var testSet []string var testKeys []string for i := 0; i < 500; i++ { - id := stringid.GenerateRandomID() + id := stringid.GenerateNonCryptoID() testSet = append(testSet, id) l := rand.Intn(12) + 12 testKeys = append(testKeys, id[:l]) @@ -382,7 +382,7 @@ func BenchmarkTruncIndexAddGet250(b *testing.B) { var testSet []string var testKeys []string for i := 0; i < 500; i++ { - id := stringid.GenerateRandomID() + id := stringid.GenerateNonCryptoID() testSet = append(testSet, id) l := rand.Intn(12) + 12 testKeys = append(testKeys, id[:l]) @@ -407,7 +407,7 @@ func BenchmarkTruncIndexAddGet500(b *testing.B) { var testSet []string var testKeys []string for i := 0; i < 500; i++ { - id := stringid.GenerateRandomID() + id := stringid.GenerateNonCryptoID() testSet = append(testSet, id) l := rand.Intn(12) + 12 testKeys = append(testKeys, id[:l]) diff --git a/utils/utils.go b/utils/utils.go index 57418fda1e..8c98d47210 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -127,7 +127,7 @@ var globalTestID string // new directory. func TestDirectory(templateDir string) (dir string, err error) { if globalTestID == "" { - globalTestID = stringid.GenerateRandomID()[:4] + globalTestID = stringid.GenerateNonCryptoID()[:4] } prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, GetCallerName(2)) if prefix == "" {