starting moduli.c port from OpenSSH
This commit is contained in:
parent
d3a5f039c1
commit
a31d50359a
@ -19,9 +19,8 @@
|
||||
|
||||
## Why?
|
||||
Compared to something like [`rsh`](https://en.wikipedia.org/wiki/Remote_Shell), SSH (*Secure SHell*) is a vast step ahead in terms of security. Since its birth, it's seen
|
||||
functionality
|
||||
increase
|
||||
by leaps and bounds. [OpenSSH](https://www.openssh.com/), by far the most deployed SSH implementation, pays special attention to security. However, due to:
|
||||
functionality increase by leaps and bounds.
|
||||
[OpenSSH](https://www.openssh.com/), by far the most deployed SSH implementation, pays special attention to security. However, due to:
|
||||
|
||||
* making various compromises for ease of use
|
||||
* unexpected vulnerabilities (are there ever any *expected* vulnerabilities?) such as [Logjam](https://weakdh.org/)
|
||||
@ -85,4 +84,4 @@ logs, and there's much better options for handling those than running SSH over T
|
||||
[isn't the silver bullet you may think it is](https://restoreprivacy.com/tor/). You are,
|
||||
of course, welcome to turn it up yourself but it is advisable to not run SSHSecure in an
|
||||
automated fashion in this case as it may revert the changes your `sshd_config`. It'll
|
||||
try not to, but it may.
|
||||
try not to, but it may.
|
||||
|
51
dh/README
Normal file
51
dh/README
Normal file
@ -0,0 +1,51 @@
|
||||
The functions found in this sub-component are ported almost directly from the
|
||||
openssh-portable[0]'s `moduli.c`[1] code (with, of course, changes made where
|
||||
appropriate to match and take advantage of Golang).
|
||||
|
||||
The OpenBSD and OpenSSH(-portable) teams have my gratitude.
|
||||
|
||||
OpenSSH/OpenSSH portable are released under a combination of the following licenses[2]:
|
||||
|
||||
* public domain
|
||||
* "BSD-style"
|
||||
* 2-, 3-, and 4-clause BSD
|
||||
* Beerware
|
||||
|
||||
The license in full for OpenSSH/OpenSSH-Portable can be found at [2].
|
||||
|
||||
The license for OpenSSH-Portable's `moduli.c` is as follows:
|
||||
|
||||
###########################################################################
|
||||
Copyright 1994 Phil Karn <karn@qualcomm.com>
|
||||
Copyright 1996-1998, 2003 William Allen Simpson <wsimpson@greendragon.com>
|
||||
Copyright 2000 Niels Provos <provos@citi.umich.edu>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
###########################################################################
|
||||
|
||||
|
||||
[0] https://www.openssh.com/portable.html
|
||||
https://anongit.mindrot.org/openssh.git
|
||||
|
||||
[1] https://anongit.mindrot.org/openssh.git/tree/moduli.c
|
||||
|
||||
[2] https://anongit.mindrot.org/openssh.git/tree/LICENCE
|
40
dh/const.go
Normal file
40
dh/const.go
Normal file
@ -0,0 +1,40 @@
|
||||
package dh
|
||||
|
||||
const (
|
||||
// QSizeMinimum Specifies the number of the most significant bit (0 to M).
|
||||
// WARNING: internally, usually 1 to N.
|
||||
QSizeMinimum = 511
|
||||
|
||||
// Prime sieving constants
|
||||
// Assuming 8 bit bytes and 32 bit words.
|
||||
ShiftBit = 3
|
||||
ShiftByte = 2
|
||||
ShiftWord = ShiftBit + ShiftByte
|
||||
ShiftMegabyte = 20
|
||||
ShiftMegaWord = ShiftMegabyte - ShiftBit
|
||||
|
||||
// Memory limits.
|
||||
// LargeMinimum is 8 megabytes
|
||||
LargeMinimum = uint32(8) // Originally an 8UL in moduli.c
|
||||
// LargeMaximum is 127MB.
|
||||
LargeMaximum = uint32(127)
|
||||
// The largest sieve prime has to be < 2**32 on 32-bit systems.
|
||||
SmallMaximum = uint32(0xffffffff) // 4294967295
|
||||
// Can sieve all primes less than 2**32, as 65537**2 > 2**32-1.
|
||||
TinyNumber = uint32(1) << 16
|
||||
// Ensure enough bit space for testing 2*q.
|
||||
TestMaximum = uint32(1) << 16
|
||||
TestMinimum = QSizeMinimum + 1 // (uint32(1) << (ShiftWord - TestPower))
|
||||
TestPower = 3 // 2**n, n < ShiftWord
|
||||
)
|
||||
|
||||
var (
|
||||
)
|
||||
|
||||
// Bit* functions operate on 32-bit words
|
||||
func BitClear(a []uint32, n uint32) (i uint32) {
|
||||
|
||||
i = a[n >> ShiftWord] &= ~(uint32(1) << (n & 31))
|
||||
|
||||
return
|
||||
}
|
36
dh/func_gen.go
Normal file
36
dh/func_gen.go
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
SSHSecure - a program to harden OpenSSH from defaults
|
||||
Copyright (C) 2020 Brent Saner
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package dh
|
||||
|
||||
/*
|
||||
OpenSSH does prime generation and primality checking a *little* weird.
|
||||
|
||||
The seemingly go-to package for DH parameter generation in Golang, github.com/Luzifer/go-dhparam,
|
||||
does implement safety checking in a way I believe to be safe (with the huge caveat that I am nowhere
|
||||
near a professional, expert, guru, etc. in mathematics, cryptography, or the like).
|
||||
|
||||
However, it is incompatible with OpenSSH's methodology for DH parameter generation.
|
||||
|
||||
1.) First, primes are generated via the Sieve of Eratosthenes.
|
||||
a.) They must also be Sophie Germain primes (where p is selected prime, 2p+1 is also prime).
|
||||
2.) Then they are filtered via Probabilistic Miller-Rabin primality tests (on both q and p, where q is (p-1)/2).
|
||||
3.) OpenSSH fully supports generators of 2, 3, and 5 whereas go-dhparam only fully supports 2 and 5.
|
||||
|
||||
And that's why I'm a sad panda and porting moduli.c to native Golang.
|
||||
*/
|
12
go.mod
Normal file
12
go.mod
Normal file
@ -0,0 +1,12 @@
|
||||
module r00t2.io/sshsecure
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/Luzifer/go-dhparam v1.1.0
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a
|
||||
github.com/go-restruct/restruct v1.2.0-alpha
|
||||
github.com/pkg/errors v0.9.1
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
|
||||
r00t2.io/sysutils v0.0.0-20210427083717-fbf1049fd285
|
||||
)
|
30
go.sum
Normal file
30
go.sum
Normal file
@ -0,0 +1,30 @@
|
||||
github.com/Luzifer/go-dhparam v1.1.0 h1:uJXDwqAVy1H4zWjmsYVmaa9yUD2Pm3SsdW4KU8d27zc=
|
||||
github.com/Luzifer/go-dhparam v1.1.0/go.mod h1:3Kuj59C67/G2EzQHjUzAryaAa70K5fqvStR2VkFLszU=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
|
||||
github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc=
|
||||
github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk=
|
||||
github.com/jszwec/csvutil v1.5.0/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
r00t2.io/sysutils v0.0.0-20210427083717-fbf1049fd285 h1:sEVsqJv1YsPToyhclbGjaZoF50w8heLifkQLZX2Jw7Y=
|
||||
r00t2.io/sysutils v0.0.0-20210427083717-fbf1049fd285/go.mod h1:XzJkBF6SHAODEszJlOcjtGoTHwYnZZNmseA6PyOujes=
|
@ -21,6 +21,7 @@ package moduli
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
`github.com/Luzifer/go-dhparam`
|
||||
"r00t2.io/sshsecure/sharedconsts"
|
||||
)
|
||||
|
||||
@ -39,7 +40,21 @@ const (
|
||||
// The recommended minimum moduli to have available.
|
||||
recMinMod int = 400
|
||||
// The minimum bits for filtering. It's generally bits - 1
|
||||
minBits uint8 = 4095
|
||||
minBits uint16 = 4096
|
||||
)
|
||||
|
||||
// Generation iterables.
|
||||
var (
|
||||
genBits = []uint16{
|
||||
4096,
|
||||
6144,
|
||||
7680,
|
||||
8192,
|
||||
}
|
||||
genGenerators = []dhparam.Generator{
|
||||
dhparam.GeneratorTwo,
|
||||
dhparam.GeneratorFive,
|
||||
}
|
||||
)
|
||||
|
||||
// The header line on the /etc/ssh/moduli file.
|
||||
@ -57,8 +72,7 @@ const (
|
||||
timeFormat string = "20060102150405" // %Y%m%d%H%M%S
|
||||
)
|
||||
|
||||
// For validation. Currently unused.
|
||||
/*
|
||||
// For validation. TODO.
|
||||
var (
|
||||
validTypes = []uint8{
|
||||
0, // Unknown, not tested
|
||||
@ -72,4 +86,3 @@ var (
|
||||
0x04, // Probabilistic Miller-Rabin primality tests.
|
||||
}
|
||||
)
|
||||
*/
|
||||
|
118
moduli/func.go
118
moduli/func.go
@ -24,42 +24,130 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
`time`
|
||||
|
||||
`github.com/Luzifer/go-dhparam`
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// getPregen gets the pregenerated moduli from upstream mirror.
|
||||
func getPregen() (Moduli, error) {
|
||||
m := Moduli{}
|
||||
// NewModuli returns a Moduli populated with Entry items.
|
||||
func NewModuli(usePreGen ... bool) (m *Moduli, err error) {
|
||||
|
||||
var doPreGen bool
|
||||
|
||||
m = new(Moduli)
|
||||
|
||||
if usePreGen != nil {
|
||||
doPreGen = usePreGen[0]
|
||||
} else {
|
||||
doPreGen = false
|
||||
}
|
||||
|
||||
if doPreGen {
|
||||
if err = GetPreGen(m); err != nil {
|
||||
return
|
||||
}
|
||||
// This may take a while.
|
||||
if err = m.Harden(); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err = Generate(m); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetPreGen gets the pregenerated moduli from upstream mirror.
|
||||
func GetPreGen(m *Moduli) (err error) {
|
||||
|
||||
var b []byte
|
||||
var goodCksum []byte
|
||||
var resp *http.Response
|
||||
|
||||
// get the pregenerated moduli
|
||||
resp, err := http.Get(pregenURL)
|
||||
resp, err = http.Get(pregenURL)
|
||||
if err != nil {
|
||||
return m, err
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return m, errors.New(fmt.Sprintf("returned status code %v: %v", resp.StatusCode, resp.Status))
|
||||
err = errors.New(fmt.Sprintf("returned status code %v: %v", resp.StatusCode, resp.Status))
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b := make([]byte, resp.ContentLength)
|
||||
|
||||
b = make([]byte, resp.ContentLength)
|
||||
if _, err = resp.Body.Read(b); err != nil {
|
||||
return m, err
|
||||
return
|
||||
}
|
||||
|
||||
// and compare the SHA3-512 (NIST) checksum.
|
||||
s := sha3.New512()
|
||||
if _, err = s.Write(b); err != nil {
|
||||
// TODO: return nil instead of b?
|
||||
return m, err
|
||||
return
|
||||
}
|
||||
goodCksum, err := hex.DecodeString(pregenCksum)
|
||||
goodCksum, err = hex.DecodeString(pregenCksum)
|
||||
if err != nil {
|
||||
return m, err
|
||||
return
|
||||
}
|
||||
|
||||
// We just compare the bytestrings.
|
||||
if bytes.Compare(s.Sum(nil), goodCksum) != 0 {
|
||||
return m, errors.New("checksums do not match")
|
||||
err = errors.New("checksums do not match")
|
||||
return
|
||||
}
|
||||
|
||||
if err := Unmarshal(b, m); err != nil {
|
||||
return m, err
|
||||
return
|
||||
}
|
||||
return m, nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Generate generates new moduli with Entry items. It's more secure than using GetPreGen (LogJam), but takes a *LOT* longer.
|
||||
func Generate(m *Moduli) (err error) {
|
||||
|
||||
var dh *dhparam.DH
|
||||
|
||||
for _, bitLen := range genBits {
|
||||
for _, generator := range genGenerators {
|
||||
|
||||
var e Entry
|
||||
|
||||
e = Entry{
|
||||
Time: time.Now(),
|
||||
Size: bitLen,
|
||||
Generator: uint8(generator),
|
||||
/*
|
||||
Type: 0,
|
||||
Tests: 0,
|
||||
Trials: 0,
|
||||
*/
|
||||
}
|
||||
|
||||
if dh, err = dhparam.Generate(int(bitLen), generator, nil); err != nil {
|
||||
continue // TODO: log/print
|
||||
}
|
||||
|
||||
// Check() applies big.Int.ProbablyPrime() (Miller-Rabin - 0x04 in ssh moduli - and Baillie-PSW test), so it's probably fine.
|
||||
if errs, ok := dh.Check(); !ok {
|
||||
_ = errs // TODO: log/print
|
||||
continue
|
||||
} else {
|
||||
e.Time = time.Now()
|
||||
// e.Type =
|
||||
// e.Tests =
|
||||
// e.Trials =
|
||||
e.Modulus = *dh.P
|
||||
|
||||
// TODO: https://stackoverflow.com/questions/18499352/golang-concurrency-how-to-append-to-the-same-slice-from-different-goroutines
|
||||
m.Params = append(m.Params, e)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
102
moduli/parser.go
102
moduli/parser.go
@ -35,102 +35,136 @@ var reSkipLine, _ = regexp.Compile(`^\s*(#.*)?$`)
|
||||
// Marshal returns the /etc/ssh/moduli format of m.
|
||||
// Format of: Time Type Tests Tries Size Generator Modulus
|
||||
// TODO: remember to write newline at end
|
||||
func (m *Moduli) Marshal() ([]byte, error) {
|
||||
func (m *Moduli) Marshal() (bytesOut []byte, err error) {
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
b.Write([]byte(header))
|
||||
for _, i := range m.Params {
|
||||
line, err := i.marshalEntry()
|
||||
if err != nil {
|
||||
return b.Bytes(), err
|
||||
return nil, err
|
||||
} else {
|
||||
b.Write(line)
|
||||
}
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
|
||||
bytesOut = b.Bytes()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// marshalEntry is used to parse a specific DH entry into the moduli.
|
||||
func (m *Entry) marshalEntry() ([]byte, error) {
|
||||
// marshalEntry is used to parse an Entry into the moduli(5) format.
|
||||
func (m *Entry) marshalEntry() (sum []byte, err error) {
|
||||
|
||||
mod := hex.EncodeToString(m.Modulus.Bytes())
|
||||
|
||||
s := fmt.Sprintf(
|
||||
"%v %v %v %v %v %v %v\n",
|
||||
m.Time.Format(timeFormat),
|
||||
string(m.Type),
|
||||
string(m.Tests),
|
||||
string(m.Trials),
|
||||
string(m.Size),
|
||||
strconv.Itoa(int(m.Size)-1), // see this thread https://twitter.com/SysAdm_Podcast/status/1386714803679399940
|
||||
string(m.Generator),
|
||||
mod,
|
||||
)
|
||||
return []byte(s), nil
|
||||
|
||||
sum = []byte(s)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Unmarshal writes the Moduli format into m from the /etc/ssh/moduli format in data.
|
||||
func Unmarshal(data []byte, m Moduli) error {
|
||||
// Unmarshal populates a Moduli from the /etc/ssh/moduli format.
|
||||
func Unmarshal(data []byte, m *Moduli) (err error) {
|
||||
|
||||
var lines []string
|
||||
var entries []Entry
|
||||
|
||||
lines = strings.Split(string(data), "\n")
|
||||
for _, line := range lines {
|
||||
|
||||
e := Entry{}
|
||||
|
||||
if reSkipLine.MatchString(line) {
|
||||
continue
|
||||
}
|
||||
|
||||
l := strings.Fields(line)
|
||||
if err := unmarshalEntry(l, e); err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
|
||||
entries = append(entries, e)
|
||||
}
|
||||
|
||||
m.Params = entries
|
||||
return nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func unmarshalEntry(line []string, m Entry) error {
|
||||
var err error
|
||||
// unmarshalEntry unmarshals a single line from an /etc/ssh/moduli into an Entry.
|
||||
func unmarshalEntry(line []string, m Entry) (err error) {
|
||||
|
||||
var modb []byte
|
||||
|
||||
if len(line) != 7 {
|
||||
return errors.New("field count mismatch")
|
||||
err = errors.New("field count mismatch")
|
||||
return
|
||||
}
|
||||
|
||||
if m.Time, err = time.Parse(timeFormat, line[0]); err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
// Numeric types. Cast to uint8. There's probably a better way to do this but golang's pretty ugly with this stuff no matter what.
|
||||
// Numeric types. Cast to uint16. There's probably a better way to do this but golang's pretty ugly with this stuff no matter what.
|
||||
// The worst part is all of them are uint8 except size (uint16).
|
||||
// Type, Tests, Trials, Size, Generator
|
||||
conv := [5]uint8{}
|
||||
conv := [5]uint16{}
|
||||
for idx := 1; idx <= 5; idx++ {
|
||||
v := line[idx]
|
||||
newv, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conv[idx-1] = uint8(newv)
|
||||
conv[idx-1] = uint16(newv)
|
||||
}
|
||||
m.Type = conv[0]
|
||||
m.Tests = conv[1]
|
||||
m.Trials = conv[2]
|
||||
m.Size = conv[3]
|
||||
m.Generator = conv[4]
|
||||
|
||||
m.Type = uint8(conv[0])
|
||||
m.Tests = uint8(conv[1])
|
||||
m.Trials = uint8(conv[2])
|
||||
m.Size = conv[3] + 1 // see this thread https://twitter.com/SysAdm_Podcast/status/1386714803679399940
|
||||
m.Generator = uint8(conv[4])
|
||||
|
||||
// And the modulus convert to big.Int.
|
||||
modb, err := hex.DecodeString(line[6])
|
||||
if err != nil {
|
||||
return err
|
||||
if modb, err = hex.DecodeString(line[6]); err != nil {
|
||||
return
|
||||
}
|
||||
m.Modulus = big.Int{}
|
||||
m.Modulus.SetBytes(modb)
|
||||
return nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Moduli) Harden() error {
|
||||
func (m *Moduli) Harden() (err error) {
|
||||
|
||||
var entries []Entry
|
||||
|
||||
for _, e := range m.Params {
|
||||
|
||||
e.Time = time.Now()
|
||||
|
||||
if e.Size >= minBits {
|
||||
entries = append(entries, e)
|
||||
}
|
||||
}
|
||||
m.Params = entries
|
||||
if len(m.Params) < recMinMod {
|
||||
return errors.New("does not meet recommended minimum moduli")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: find way of testing/sieving primes
|
||||
if len(m.Params) < recMinMod {
|
||||
err = errors.New("does not meet recommended minimum moduli")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: find way of testing/sieving primes
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -5,4 +5,5 @@ https://security.stackexchange.com/a/113058
|
||||
https://github.com/Luzifer/go-dhparam
|
||||
https://github.com/mimoo/test_DHparams
|
||||
https://github.com/hyperreality/cryptopals-2/blob/517c1907b2041e6f7ef18930eca2aa3a24fb73d8/dh.go
|
||||
https://sosedoff.com/2016/07/16/golang-struct-tags.html
|
||||
https://sosedoff.com/2016/07/16/golang-struct-tags.html
|
||||
port moduli gen? https://github.com/openssh/openssh-portable/blob/master/moduli.c
|
||||
|
@ -29,7 +29,7 @@ type Moduli struct {
|
||||
Params []Entry
|
||||
}
|
||||
|
||||
// Moduli is a struct reflecting the format of a single /etc/ssh/moduli entry. See moduli(5) for details.
|
||||
// Entry is a struct reflecting the format of a single /etc/ssh/moduli entry. See moduli(5) for details.
|
||||
type Entry struct {
|
||||
Time time.Time // YYYYMMDDHHSS
|
||||
/*
|
||||
@ -64,7 +64,7 @@ type Entry struct {
|
||||
// man 5 moduli:
|
||||
Decimal number indicating the size of the prime in bits.
|
||||
*/
|
||||
Size uint8
|
||||
Size uint16
|
||||
/*
|
||||
// man 5 moduli:
|
||||
The recommended generator for use with this modulus (hexadecimal).
|
||||
|
Loading…
Reference in New Issue
Block a user