@@ -44,20 +44,35 @@ const (
44
44
//
45
45
//nolint:varnamelen
46
46
func unbiasedModulo32 (v uint32 , n int32 ) (int32 , error ) {
47
- prod := uint64 (v ) * uint64 (n ) // #nosec G115 -- uint32 to uint64 is always safe
48
- low := uint32 (prod ) // #nosec G115 -- truncation is intentional for the algorithm
49
- if low < uint32 (n ) { // #nosec G115 -- int32 to uint32 is safe for positive n (we require n > 0)
50
- thresh := uint32 (- n ) % uint32 (n ) // #nosec G115 -- int32 to uint32 after negation is an acceptable pattern here
47
+ // Validate n is positive
48
+ if n <= 0 {
49
+ return 0 , xerrors .Errorf ("modulus must be positive: %d" , n )
50
+ }
51
+
52
+ // These conversions are safe:
53
+ // - uint32 to uint64 is always safe (smaller to larger)
54
+ // - int32 to uint64 is safe for positive values, which we've validated
55
+ prod := uint64 (v ) * uint64 (n )
56
+
57
+ // Intentional truncation for algorithm
58
+ low := uint32 (prod )
59
+
60
+ if low < uint32 (n ) {
61
+ // This conversion is safe since n is positive, so -n as uint32 is well-defined
62
+ thresh := uint32 (- n ) % uint32 (n )
63
+
51
64
for low < thresh {
52
65
err := binary .Read (rand .Reader , binary .BigEndian , & v )
53
66
if err != nil {
54
67
return 0 , err
55
68
}
56
- prod = uint64 (v ) * uint64 (n ) // #nosec G115 -- uint32 to uint64 is always safe
57
- low = uint32 (prod ) // #nosec G115 -- truncation is intentional for the algorithm
69
+ prod = uint64 (v ) * uint64 (n )
70
+ low = uint32 (prod )
58
71
}
59
72
}
60
- return int32 (prod >> 32 ), nil // #nosec G115 -- proper range is guaranteed by the algorithm
73
+
74
+ // The algorithm ensures prod>>32 is always in [0,n), so conversion to int32 is safe
75
+ return int32 (prod >> 32 ), nil
61
76
}
62
77
63
78
// StringCharset generates a random string using the provided charset and size.
@@ -87,10 +102,14 @@ func StringCharset(charSetStr string, size int) (string, error) {
87
102
r := binary .BigEndian .Uint32 (entropy [:4 ]) // #nosec G115 -- not a conversion, just reading bytes as uint32
88
103
entropy = entropy [4 :]
89
104
90
- // Charset length is limited by string size, so conversion to int32 is safe
105
+ // Ensure charset length is within int32 range
106
+ charSetLen := len (charSet )
107
+ if charSetLen <= 0 || charSetLen > (1 << 31 )- 1 {
108
+ return "" , xerrors .Errorf ("invalid charset length: %d" , charSetLen )
109
+ }
91
110
ci , err := unbiasedModulo32 (
92
111
r ,
93
- int32 (len ( charSet )), // #nosec G115 -- int to int32 is safe for charset length
112
+ int32 (charSetLen ),
94
113
)
95
114
if err != nil {
96
115
return "" , err
0 commit comments