From b903b535d3ef82fab12a9cc0fa50fccc396ced55 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 9 Jul 2025 14:08:52 -0400 Subject: [PATCH 01/37] acme: capture pebble test subprocess stdout/stderr When spawning the pebble and pebble-challtestserv processes redirect stdout/stderr to bytes.Buffer instances and print their content at test end as appropriate. The stdout/stderr content for each process is printed if the test failed, or if testing is being done in verbose mode. Otherwise the output is swallowed. This makes debugging test failures much easier as output from the subprocesses from independent tests isn't intermingled. Updates golang/go#74437 Cq-Include-Trybots: luci.golang.try:x_crypto-gotip-linux-amd64-longtest Change-Id: Ia79a3609ce3522ef6248442de247554c39367162 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/686935 Auto-Submit: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI --- acme/pebble_test.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/acme/pebble_test.go b/acme/pebble_test.go index 63e6cc5836..af7aee67d2 100644 --- a/acme/pebble_test.go +++ b/acme/pebble_test.go @@ -776,14 +776,28 @@ func prepareBinaries(t *testing.T, pebbleDir string) string { func spawnServerProcess(t *testing.T, dir string, cmd string, args ...string) { t.Helper() + var stdout, stderr bytes.Buffer + cmdInstance := exec.Command("./"+cmd, args...) cmdInstance.Dir = dir - cmdInstance.Stdout = os.Stdout - cmdInstance.Stderr = os.Stderr + cmdInstance.Stdout = &stdout + cmdInstance.Stderr = &stderr + if err := cmdInstance.Start(); err != nil { t.Fatalf("failed to start %s: %v", cmd, err) } + t.Cleanup(func() { cmdInstance.Process.Kill() + + if t.Failed() || testing.Verbose() { + t.Logf("=== %s output ===", cmd) + if stdout.Len() > 0 { + t.Logf("stdout:\n%s", strings.TrimSpace(stdout.String())) + } + if stderr.Len() > 0 { + t.Logf("stderr:\n%s", strings.TrimSpace(stderr.String())) + } + } }) } From 1b4c3d2e8c8be172c6af8f2f72778e69e74d2e78 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Mon, 14 Jul 2025 16:00:58 +0000 Subject: [PATCH 02/37] x509roots/fallback: update bundle This is an automated CL which updates the NSS root bundle. [git-generate] go generate ./x509roots Change-Id: Ib30b702d41dedacce835628a9dab456098be0703 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/687895 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Auto-Submit: Gopher Robot --- x509roots/fallback/bundle.go | 132 +++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/x509roots/fallback/bundle.go b/x509roots/fallback/bundle.go index 19a168c4bb..bb26698790 100644 --- a/x509roots/fallback/bundle.go +++ b/x509roots/fallback/bundle.go @@ -3263,6 +3263,43 @@ Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- +`, + }, + { + cn: "CN=SwissSign RSA TLS Root CA 2022 - 1,O=SwissSign AG,C=CH", + sha256Hash: "193144f431e0fddb740717d4de926a571133884b4360d30e272913cbe660ce41", + pem: `-----BEGIN CERTIFICATE----- +MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UE +AxMiU3dpc3NTaWduIFJTQSBUTFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgx +MTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxT +d2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0EgVExTIFJvb3QgQ0Eg +MjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmjiC8NX +vDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7 +LCTLf5ImgKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX +5XH8irCRIFucdFJtrhUnWXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyE +EPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlfGUEGjw5NBuBwQCMBauTLE5tzrE0USJIt +/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36qOTw7D59Ke4LKa2/KIj4x +0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLOEGrOyvi5 +KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM +0ZPlEuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shd +OxtYk8EXlFXIC+OCeYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrta +clXvyFu1cvh43zcgTFeRc5JzrBh3Q4IgaezprClG5QtO+DdziZaKHG29777YtvTK +wP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQABo2MwYTAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow4UD2p8P98Q+4 +DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL +BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO3 +10aewCoSPY6WlkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgz +Hqp41eZUBDqyggmNzhYzWUUo8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQ +iJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zpy1FVCypM9fJkT6lc/2cyjlUtMoIc +gC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3CjlvrzG4ngRhZi0Rjn9UM +ZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6MOuhF +LhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJp +zv1/THfQwUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/Td +Ao9QAwKxuDdollDruF/UKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0 +rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0nhzck5npgL7XTgwSqT0N1osGDsieYK7EO +gLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rwtnu64ZzZ +-----END CERTIFICATE----- `, }, { @@ -3606,6 +3643,62 @@ AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj /bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== -----END CERTIFICATE----- +`, + }, + { + cn: "CN=TrustAsia TLS ECC Root CA,O=TrustAsia Technologies\\, Inc.,C=CN", + sha256Hash: "c0076b9ef0531fb1a656d67c4ebe97cd5dbaa41ef44598acc2489878c92d8711", + pem: `-----BEGIN CERTIFICATE----- +MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMw +WDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQw +NTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBYMQswCQYDVQQGEwJDTjElMCMGA1UE +ChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1c3RB +c2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/pVs/ +AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDp +guMqWzJ8S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAw +DgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01 +L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15KeAIxAKORh/IRM4PDwYqR +OkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ== +-----END CERTIFICATE----- +`, + }, + { + cn: "CN=TrustAsia TLS RSA Root CA,O=TrustAsia Technologies\\, Inc.,C=CN", + sha256Hash: "06c08d7dafd876971eb1124fe67f847ec0c7a158d3ea53cbe940e2ea9791f4c3", + pem: `-----BEGIN CERTIFICATE----- +MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEM +BQAwWDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcN +MjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2WjBYMQswCQYDVQQGEwJDTjElMCMG +A1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1 +c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+ +NmDQDIPNlOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJ +Q1DNDX3eRA5gEk9bNb2/mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561 +HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fkzv93uMltrOXVmPGZLmzjyUT5tUMnCE32 +ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYozza/+lcK7Fs/6TAWe8Tb +xNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyrz2I8sMeX +i9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQ +UNoyIBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+j +TnhMmCWr8n4uIF6CFabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DT +bE3txci3OE9kxJRMT6DNrqXGJyV1J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8 +S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnTq1mt1tve1CuBAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZylomkadFK/hT +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3 +Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4 +iqME3mmL5Dw8veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt +7DlK9RME7I10nYEKqG/odv6LTytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp +2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHxtlotJnMnlvm5P1vQiJ3koP26TpUJ +g3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp27RIGAAtvKLEiUUj +pQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87qqA8M +pugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongP +XvPKnbwbPKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIwe +SsCI3zWQzj8C9GRh3sfIB5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0 +ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNzFrwFuHnYWa8G5z9nODmxfKuU4CkUpijy +323imttUQ/hHWKNddBWcwauwxzQ= +-----END CERTIFICATE----- `, }, { @@ -4150,6 +4243,45 @@ i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN -----END CERTIFICATE----- `, }, + { + cn: "OU=ePKI Root Certification Authority,O=Chunghwa Telecom Co.\\, Ltd.,C=TW", + sha256Hash: "c0a6f4dc63a24bfdcf54ef2a6a082a0a72de35803e2ff5ff527ae5d87206dfd5", + pem: `-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- +`, + distrustAfter: "2025-04-15T23:59:59Z", + }, { cn: "SERIALNUMBER=G63287510,CN=ANF Secure Server Root CA,OU=ANF CA Raiz,O=ANF Autoridad de Certificacion,C=ES", sha256Hash: "fb8fec759169b9106b1e511644c618c51304373f6c0643088d8beffd1b997599", From 1fda73153feef7b246f24005838c387e354e5e3b Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 31 Jul 2025 13:53:34 -0400 Subject: [PATCH 03/37] acme: increase pebble test waitForServer attempts In CI it seems that occasionally we can't connect to the test servers within 10 tries, and the test flakes. Let's give the process more attempts. Updates golang/go#74437 Change-Id: I74d6cea83468a3a572ec4b52ff7314c778c664cf Cq-Include-Trybots: luci.golang.try:x_crypto-gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/crypto/+/692075 Auto-Submit: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Mark Freeman LUCI-TryBot-Result: Go LUCI --- acme/pebble_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acme/pebble_test.go b/acme/pebble_test.go index af7aee67d2..e3738497a5 100644 --- a/acme/pebble_test.go +++ b/acme/pebble_test.go @@ -692,14 +692,14 @@ func startPebbleEnvironment(t *testing.T, config *environmentConfig) environment func waitForServer(t *testing.T, addr string) { t.Helper() - for i := 0; i < 10; i++ { + for i := 0; i < 20; i++ { if conn, err := net.Dial("tcp", addr); err == nil { conn.Close() return } time.Sleep(time.Duration(i*100) * time.Millisecond) } - t.Fatalf("failed to connect to %q after 10 tries", addr) + t.Fatalf("failed to connect to %q after 20 tries", addr) } // fetchModule fetches the module at the given version and returns the directory From c247dead11de7671a21a6c5169555e2aa5313caa Mon Sep 17 00:00:00 2001 From: Mateusz Poliwczak Date: Sun, 25 May 2025 16:41:48 +0200 Subject: [PATCH 04/37] x509roots/fallback: store bundle certs directly in DER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit goos: linux goarch: amd64 pkg: golang.org/x/crypto/x509roots/fallback cpu: AMD Ryzen 5 4600G with Radeon Graphics │ /tmp/before │ /tmp/after │ │ sec/op │ sec/op vs base │ InitTime-12 1.726m ± 0% 1.101m ± 1% -36.20% (p=0.000 n=30) │ /tmp/before │ /tmp/after │ │ B/op │ B/op vs base │ InitTime-12 1178.2Ki ± 0% 779.8Ki ± 0% -33.81% (p=0.000 n=30) │ /tmp/before │ /tmp/after │ │ allocs/op │ allocs/op vs base │ InitTime-12 11.35k ± 0% 10.64k ± 0% -6.32% (p=0.000 n=30) Updates golang/go#73691 Change-Id: Ic33f2fdfc65001c41afeb3b6af8a383288d10de6 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/676217 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Mark Freeman --- x509roots/fallback/bundle.der | Bin 0 -> 154797 bytes x509roots/fallback/bundle.go | 5139 +++++------------------------ x509roots/fallback/bundle_test.go | 32 + x509roots/fallback/fallback.go | 26 +- x509roots/gen_fallback_bundle.go | 28 +- 5 files changed, 911 insertions(+), 4314 deletions(-) create mode 100644 x509roots/fallback/bundle.der create mode 100644 x509roots/fallback/bundle_test.go diff --git a/x509roots/fallback/bundle.der b/x509roots/fallback/bundle.der new file mode 100644 index 0000000000000000000000000000000000000000..1abf12f5980415e088cfe616e3c01c9fb5eb2108 GIT binary patch literal 154797 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ⅈ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 Date: Wed, 6 Aug 2025 12:43:58 -0400 Subject: [PATCH 05/37] acme: fix pebble subprocess output data race Wait for process completion before reading stdout/stderr buffers to eliminate race between I/O Go routines and test cleanup. Updates golang/go#74437 Cq-Include-Trybots: luci.golang.try:x_crypto-gotip-linux-amd64-longtest-race Change-Id: I2e650c04db5be0d7a1e858ce40e25f13ad12223c Reviewed-on: https://go-review.googlesource.com/c/crypto/+/693596 Auto-Submit: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- acme/pebble_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/acme/pebble_test.go b/acme/pebble_test.go index e3738497a5..b633435a71 100644 --- a/acme/pebble_test.go +++ b/acme/pebble_test.go @@ -789,6 +789,7 @@ func spawnServerProcess(t *testing.T, dir string, cmd string, args ...string) { t.Cleanup(func() { cmdInstance.Process.Kill() + cmdInstance.Wait() if t.Failed() || testing.Verbose() { t.Logf("=== %s output ===", cmd) From ef5341b70697ceb55f904384bd982587224e8b0c Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Thu, 7 Aug 2025 09:08:13 -0700 Subject: [PATCH 06/37] go.mod: update golang.org/x dependencies Update golang.org/x dependencies to their latest tagged versions. Change-Id: I93de641462a54b0ae565bb60e2a0e6e7c2c3b883 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/693999 LUCI-TryBot-Result: Go LUCI Auto-Submit: Gopher Robot Reviewed-by: Dmitri Shuralyov Reviewed-by: David Chase --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 5cd0c6410d..4ba08a1445 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module golang.org/x/crypto go 1.23.0 require ( - golang.org/x/net v0.41.0 // tagx:ignore - golang.org/x/sys v0.34.0 - golang.org/x/term v0.33.0 + golang.org/x/net v0.42.0 // tagx:ignore + golang.org/x/sys v0.35.0 + golang.org/x/term v0.34.0 ) -require golang.org/x/text v0.27.0 // indirect +require golang.org/x/text v0.28.0 // indirect diff --git a/go.sum b/go.sum index 93d2855a8c..b75af8566b 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= From 44ecf3af9978b32529ce689a6964bd557c79aa1c Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Wed, 13 Aug 2025 14:21:40 +0000 Subject: [PATCH 07/37] all: upgrade go directive to at least 1.24.0 [generated] By now Go 1.25.0 has been released, and Go 1.23 is no longer supported per the Go Release Policy (see https://go.dev/doc/devel/release#policy). For golang/go#69095. [git-generate] (cd . && go get go@1.24.0 && go mod tidy && go fix ./... && go mod edit -toolchain=none) (cd x509roots/fallback && go get go@1.24.0 && go mod tidy && go fix ./... && go mod edit -toolchain=none) Change-Id: Ia4c201e9611a2c13489e16d4ae81d7e3e32bf455 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/695715 Auto-Submit: Gopher Robot LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: David Chase --- go.mod | 2 +- x509roots/fallback/go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4ba08a1445..4ccce30fb4 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module golang.org/x/crypto -go 1.23.0 +go 1.24.0 require ( golang.org/x/net v0.42.0 // tagx:ignore diff --git a/x509roots/fallback/go.mod b/x509roots/fallback/go.mod index 6ffde44ff8..5d4b07eee5 100644 --- a/x509roots/fallback/go.mod +++ b/x509roots/fallback/go.mod @@ -1,3 +1,3 @@ module golang.org/x/crypto/x509roots/fallback -go 1.23.0 +go 1.24.0 From f5a2eabcab987dc84f30d5479ed5c5605b5de634 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 18 Aug 2025 18:57:42 +0200 Subject: [PATCH 08/37] ssh: use curve25519.X25519 instead of curve25519.ScalarMult This lets us surface an error message instead of panicking if running in fips140=only mode, where ECDH on X25519 returns an error. Updates golang/go#75061 Change-Id: I6a6a6964c0591f3dca2dc946c99d44364314a3ab Reviewed-on: https://go-review.googlesource.com/c/crypto/+/696995 Reviewed-by: Carlos Amedee Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Nicola Murino --- ssh/kex.go | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/ssh/kex.go b/ssh/kex.go index cf388a92aa..368624759d 100644 --- a/ssh/kex.go +++ b/ssh/kex.go @@ -9,7 +9,6 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" - "crypto/subtle" "encoding/binary" "errors" "fmt" @@ -454,15 +453,17 @@ func (kp *curve25519KeyPair) generate(rand io.Reader) error { if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { return err } - curve25519.ScalarBaseMult(&kp.pub, &kp.priv) + p, err := curve25519.X25519(kp.priv[:], curve25519.Basepoint) + if err != nil { + return fmt.Errorf("curve25519: %w", err) + } + if len(p) != 32 { + return fmt.Errorf("curve25519: internal error: X25519 returned %d bytes, expected 32", len(p)) + } + copy(kp.pub[:], p) return nil } -// curve25519Zeros is just an array of 32 zero bytes so that we have something -// convenient to compare against in order to reject curve25519 points with the -// wrong order. -var curve25519Zeros [32]byte - func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { var kp curve25519KeyPair if err := kp.generate(rand); err != nil { @@ -485,11 +486,9 @@ func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handsh return nil, errors.New("ssh: peer's curve25519 public value has wrong length") } - var servPub, secret [32]byte - copy(servPub[:], reply.EphemeralPubKey) - curve25519.ScalarMult(&secret, &kp.priv, &servPub) - if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { - return nil, errors.New("ssh: peer's curve25519 public value has wrong order") + secret, err := curve25519.X25519(kp.priv[:], reply.EphemeralPubKey) + if err != nil { + return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err) } h := crypto.SHA256.New() @@ -531,11 +530,9 @@ func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handsh return nil, err } - var clientPub, secret [32]byte - copy(clientPub[:], kexInit.ClientPubKey) - curve25519.ScalarMult(&secret, &kp.priv, &clientPub) - if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { - return nil, errors.New("ssh: peer's curve25519 public value has wrong order") + secret, err := curve25519.X25519(kp.priv[:], kexInit.ClientPubKey) + if err != nil { + return nil, fmt.Errorf("ssh: peer's curve25519 public value is not valid: %w", err) } hostKeyBytes := priv.PublicKey().Marshal() From b8d8dae13d7dda8706ca2ab98934ad404aacae22 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 18 Aug 2025 19:06:50 +0200 Subject: [PATCH 09/37] curve25519: include potential fips140=only error in panic message Updates golang/go#75061 Change-Id: I6a6a696474122a12c12696d8a2efec902572327d Reviewed-on: https://go-review.googlesource.com/c/crypto/+/696996 Reviewed-by: Nicola Murino Auto-Submit: Filippo Valsorda Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee --- curve25519/curve25519.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curve25519/curve25519.go b/curve25519/curve25519.go index 21ca3b2ee4..8ff087df4c 100644 --- a/curve25519/curve25519.go +++ b/curve25519/curve25519.go @@ -36,7 +36,7 @@ func ScalarBaseMult(dst, scalar *[32]byte) { curve := ecdh.X25519() priv, err := curve.NewPrivateKey(scalar[:]) if err != nil { - panic("curve25519: internal error: scalarBaseMult was not 32 bytes") + panic("curve25519: " + err.Error()) } copy(dst[:], priv.PublicKey().Bytes()) } From a4d1237429d6056ef197b0b911b8b9d7dca8ecf6 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sat, 9 Aug 2025 19:56:31 +0200 Subject: [PATCH 10/37] ssh/knownhosts: improve IPv6 support in Normalize Correctly converts bracketed IPv6: - [abcd::abcd:abcd:abcd] => abcd::abcd:abcd:abcd - [abcd::abcd:abcd:abcd]:22 => abcd::abcd:abcd:abcd - [abcd::abcd:abcd:abcd]:23 => [abcd::abcd:abcd:abcd]:23 Fixes golang/go#53463 Change-Id: Id0a7460d8448a72e2a8c6d46137245bead9ecf9f Reviewed-on: https://go-review.googlesource.com/c/crypto/+/694575 LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda Reviewed-by: David Chase Reviewed-by: Carlos Amedee --- ssh/knownhosts/knownhosts.go | 22 ++++++++++++++-------- ssh/knownhosts/knownhosts_test.go | 29 ++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/ssh/knownhosts/knownhosts.go b/ssh/knownhosts/knownhosts.go index c022e411f0..1ebd7e6da2 100644 --- a/ssh/knownhosts/knownhosts.go +++ b/ssh/knownhosts/knownhosts.go @@ -421,20 +421,26 @@ func New(files ...string) (ssh.HostKeyCallback, error) { return certChecker.CheckHostKey, nil } -// Normalize normalizes an address into the form used in known_hosts +// Normalize normalizes an address into the form used in known_hosts. Supports +// IPv4, hostnames, bracketed IPv6. Any other non-standard formats are returned +// with minimal transformation. func Normalize(address string) string { + const defaultSSHPort = "22" + host, port, err := net.SplitHostPort(address) if err != nil { host = address - port = "22" + port = defaultSSHPort + } + + if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { + host = host[1 : len(host)-1] } - entry := host - if port != "22" { - entry = "[" + entry + "]:" + port - } else if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") { - entry = "[" + entry + "]" + + if port == defaultSSHPort { + return host } - return entry + return "[" + host + "]:" + port } // Line returns a line to add append to the known_hosts files. diff --git a/ssh/knownhosts/knownhosts_test.go b/ssh/knownhosts/knownhosts_test.go index 156576ad07..552a556110 100644 --- a/ssh/knownhosts/knownhosts_test.go +++ b/ssh/knownhosts/knownhosts_test.go @@ -236,7 +236,7 @@ func TestLine(t *testing.T) { "server.org": "server.org " + edKeyStr, "server.org:22": "server.org " + edKeyStr, "server.org:23": "[server.org]:23 " + edKeyStr, - "[c629:1ec4:102:304:102:304:102:304]:22": "[c629:1ec4:102:304:102:304:102:304] " + edKeyStr, + "[c629:1ec4:102:304:102:304:102:304]:22": "c629:1ec4:102:304:102:304:102:304 " + edKeyStr, "[c629:1ec4:102:304:102:304:102:304]:23": "[c629:1ec4:102:304:102:304:102:304]:23 " + edKeyStr, } { if got := Line([]string{in}, edKey); got != want { @@ -310,14 +310,25 @@ func testHostHash(t *testing.T, hostname, encoded string) { func TestNormalize(t *testing.T) { for in, want := range map[string]string{ - "127.0.0.1:22": "127.0.0.1", - "[127.0.0.1]:22": "127.0.0.1", - "[127.0.0.1]:23": "[127.0.0.1]:23", - "127.0.0.1:23": "[127.0.0.1]:23", - "[a.b.c]:22": "a.b.c", - "[abcd:abcd:abcd:abcd]": "[abcd:abcd:abcd:abcd]", - "[abcd:abcd:abcd:abcd]:22": "[abcd:abcd:abcd:abcd]", - "[abcd:abcd:abcd:abcd]:23": "[abcd:abcd:abcd:abcd]:23", + "127.0.0.1": "127.0.0.1", + "127.0.0.1:22": "127.0.0.1", + "[127.0.0.1]:22": "127.0.0.1", + "[127.0.0.1]:23": "[127.0.0.1]:23", + "127.0.0.1:23": "[127.0.0.1]:23", + "[a.b.c]:22": "a.b.c", + "[a.b.c]:23": "[a.b.c]:23", + "abcd::abcd:abcd:abcd": "abcd::abcd:abcd:abcd", + "[abcd::abcd:abcd:abcd]": "abcd::abcd:abcd:abcd", + "[abcd::abcd:abcd:abcd]:22": "abcd::abcd:abcd:abcd", + "[abcd::abcd:abcd:abcd]:23": "[abcd::abcd:abcd:abcd]:23", + "2001:db8::1": "2001:db8::1", + "2001:db8::1:22": "2001:db8::1:22", + "[2001:db8::1]:22": "2001:db8::1", + "2001:db8::1:2200": "2001:db8::1:2200", + "a.b.c.d.com:2200": "[a.b.c.d.com]:2200", + "2001::db8:1": "2001::db8:1", + "2001::db8:1:22": "2001::db8:1:22", + "2001::db8:1:2200": "2001::db8:1:2200", } { got := Normalize(in) if got != want { From 8f580defa01dec23898d3cd27f6369cdcc62f71f Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 24 Aug 2025 10:53:36 +0200 Subject: [PATCH 11/37] ssh: remove Go 1.24 build tag for ML-KEM kex Change-Id: Ia77ad1b6fef9919ab100fb10c42231725eb81c12 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/698775 LUCI-TryBot-Result: Go LUCI Auto-Submit: Nicola Murino Reviewed-by: Filippo Valsorda Reviewed-by: Cherry Mui Reviewed-by: Roland Shoemaker --- ssh/common.go | 2 ++ ssh/kex.go | 1 + ssh/mlkem.go | 15 --------------- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/ssh/common.go b/ssh/common.go index f2ec0896c2..8bfad16c41 100644 --- a/ssh/common.go +++ b/ssh/common.go @@ -83,6 +83,7 @@ var ( // supportedKexAlgos specifies key-exchange algorithms implemented by this // package in preference order, excluding those with security issues. supportedKexAlgos = []string{ + KeyExchangeMLKEM768X25519, KeyExchangeCurve25519, KeyExchangeECDHP256, KeyExchangeECDHP384, @@ -94,6 +95,7 @@ var ( // defaultKexAlgos specifies the default preference for key-exchange // algorithms in preference order. defaultKexAlgos = []string{ + KeyExchangeMLKEM768X25519, KeyExchangeCurve25519, KeyExchangeECDHP256, KeyExchangeECDHP384, diff --git a/ssh/kex.go b/ssh/kex.go index 368624759d..78aaf03103 100644 --- a/ssh/kex.go +++ b/ssh/kex.go @@ -438,6 +438,7 @@ func init() { kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{} kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} + kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{} } // curve25519sha256 implements the curve25519-sha256 (formerly known as diff --git a/ssh/mlkem.go b/ssh/mlkem.go index 657e1079d4..ddc0ed1fc0 100644 --- a/ssh/mlkem.go +++ b/ssh/mlkem.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.24 - package ssh import ( @@ -13,23 +11,10 @@ import ( "errors" "fmt" "io" - "runtime" - "slices" "golang.org/x/crypto/curve25519" ) -func init() { - // After Go 1.24rc1 mlkem swapped the order of return values of Encapsulate. - // See #70950. - if runtime.Version() == "go1.24rc1" { - return - } - supportedKexAlgos = slices.Insert(supportedKexAlgos, 0, KeyExchangeMLKEM768X25519) - defaultKexAlgos = slices.Insert(defaultKexAlgos, 0, KeyExchangeMLKEM768X25519) - kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{} -} - // mlkem768WithCurve25519sha256 implements the hybrid ML-KEM768 with // curve25519-sha256 key exchange method, as described by // draft-kampanakis-curdle-ssh-pq-ke-05 section 2.3.3. From 9d779377cff7ff1f58520cc044fb90b10ddfc561 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 11 Jun 2025 17:43:01 -0400 Subject: [PATCH 12/37] acme: include order problem in OrderError If client.WaitOrder or client.CreateOrderCert return an acme.OrderError it's helpful to include the order's problem field (if available). This will often have detailed information about why a particular order became invalid that's invaluable for debugging (e.g. a challenge response was incorrect, a name couldn't be resolved, etc). While it's possible for a consumer to poll the order themselves as part of handling the order to extract a fresh Order.Error field value, it would take an extra round-trip network request. Since we have the underlying error in-hand when we produce the OrderError we might as well include it directly. Since this field is a structured object with a number of sub-fields the OrderError.Error() function isn't updated to include the order problem error in the String description. Interested callers should instead use errors.Is to extract the problem information directly. Resolves golang/go#74430 Cq-Include-Trybots: luci.golang.try:x_crypto-gotip-linux-amd64-longtest Change-Id: I3158f064793bbfdc292dd6b5e1a6bfd7729bd980 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/681037 Auto-Submit: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Michael Pratt Reviewed-by: Ian Stapleton Cordasco LUCI-TryBot-Result: Go LUCI --- acme/pebble_test.go | 7 ++++++- acme/rfc8555.go | 4 ++-- acme/rfc8555_test.go | 19 ++++++++++++++++--- acme/types.go | 5 ++++- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/acme/pebble_test.go b/acme/pebble_test.go index b633435a71..bb4809faf7 100644 --- a/acme/pebble_test.go +++ b/acme/pebble_test.go @@ -382,7 +382,12 @@ func testIssuance(t *testing.T, env *environment, challSrv challengeServer) { // Wait for the order to become ready for finalization. order, err = client.WaitOrder(ctx, order.URI) if err != nil { - t.Fatalf("failed to wait for order %s: %s", orderURL, err) + var orderErr *acme.OrderError + if errors.Is(err, orderErr) { + t.Fatalf("failed to wait for order %s: %s: %s", orderURL, err, orderErr.Problem) + } else { + t.Fatalf("failed to wait for order %s: %s", orderURL, err) + } } if order.Status != acme.StatusReady { t.Fatalf("expected order %s status to be ready, got %v", diff --git a/acme/rfc8555.go b/acme/rfc8555.go index 3152e531b6..fc653f3f0b 100644 --- a/acme/rfc8555.go +++ b/acme/rfc8555.go @@ -272,7 +272,7 @@ func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) { case err != nil: // Skip and retry. case o.Status == StatusInvalid: - return nil, &OrderError{OrderURL: o.URI, Status: o.Status} + return nil, &OrderError{OrderURL: o.URI, Status: o.Status, Problem: o.Error} case o.Status == StatusReady || o.Status == StatusValid: return o, nil } @@ -369,7 +369,7 @@ func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bu } // The only acceptable status post finalize and WaitOrder is "valid". if o.Status != StatusValid { - return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status} + return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status, Problem: o.Error} } crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle) return crt, o.CertURL, err diff --git a/acme/rfc8555_test.go b/acme/rfc8555_test.go index d65720a356..e9cedb5927 100644 --- a/acme/rfc8555_test.go +++ b/acme/rfc8555_test.go @@ -885,11 +885,17 @@ func TestRFC_WaitOrderError(t *testing.T) { s.handle("/orders/1", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Location", s.url("/orders/1")) w.WriteHeader(http.StatusOK) - s := StatusPending if count > 0 { - s = StatusInvalid + // https://www.rfc-editor.org/rfc/rfc8555#section-7.3.3 + errorData := `{ + "type": "urn:ietf:params:acme:error:userActionRequired", + "detail": "Terms of service have changed", + "instance": "https://example.com/acme/agreement/?token=W8Ih3PswD-8" + }` + fmt.Fprintf(w, `{"status": %q, "error": %s}`, StatusInvalid, errorData) + } else { + fmt.Fprintf(w, `{"status": %q}`, StatusPending) } - fmt.Fprintf(w, `{"status": %q}`, s) count++ }) s.start() @@ -910,6 +916,13 @@ func TestRFC_WaitOrderError(t *testing.T) { if e.Status != StatusInvalid { t.Errorf("e.Status = %q; want %q", e.Status, StatusInvalid) } + if e.Problem == nil { + t.Errorf("e.Problem = nil") + } + expectedProbType := "urn:ietf:params:acme:error:userActionRequired" + if e.Problem.ProblemType != expectedProbType { + t.Errorf("e.Problem.ProblemType = %q; want %q", e.Problem.ProblemType, expectedProbType) + } } func TestRFC_CreateOrderCert(t *testing.T) { diff --git a/acme/types.go b/acme/types.go index c466645ca1..322640c453 100644 --- a/acme/types.go +++ b/acme/types.go @@ -154,13 +154,16 @@ func (a *AuthorizationError) Error() string { // OrderError is returned from Client's order related methods. // It indicates the order is unusable and the clients should start over with -// AuthorizeOrder. +// AuthorizeOrder. A Problem description may be provided with details on +// what caused the order to become unusable. // // The clients can still fetch the order object from CA using GetOrder // to inspect its state. type OrderError struct { OrderURL string Status string + // Problem is the error that occurred while processing the order. + Problem *Error } func (oe *OrderError) Error() string { From 5307a0ce6db8057c8d7c4378dc4bd715b4985ba1 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Sun, 7 Sep 2025 20:55:38 -0700 Subject: [PATCH 13/37] go.mod: update golang.org/x dependencies Update golang.org/x dependencies to their latest tagged versions. Change-Id: I75e16a930bfe42cc082df82ab67802c42ad56a97 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/701303 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Michael Pratt Auto-Submit: Gopher Robot --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 4ccce30fb4..fd65b61893 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module golang.org/x/crypto go 1.24.0 require ( - golang.org/x/net v0.42.0 // tagx:ignore - golang.org/x/sys v0.35.0 - golang.org/x/term v0.34.0 + golang.org/x/net v0.43.0 // tagx:ignore + golang.org/x/sys v0.36.0 + golang.org/x/term v0.35.0 ) -require golang.org/x/text v0.28.0 // indirect +require golang.org/x/text v0.29.0 // indirect diff --git a/go.sum b/go.sum index b75af8566b..c3f2d576cb 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= From 559e062ce8bfd6a39925294620b50906ca2a6f95 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 31 Aug 2025 20:07:32 +0200 Subject: [PATCH 14/37] ssh/agent: return an error for unexpected message types Previously, receiving an unexpected message type in response to a key listing or a signing request could cause a panic due to a failed type assertion. This change adds a default case to the type switch in order to detect and explicitly handle unknown or invalid message types, returning a descriptive error instead of crashing. Fixes golang/go#75178 Change-Id: Icbc3432adc79fe3c56b1ff23c6724d7a6f710f3a Reviewed-on: https://go-review.googlesource.com/c/crypto/+/700295 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt Reviewed-by: Jakub Ciolek --- ssh/agent/client.go | 6 +++-- ssh/agent/client_test.go | 48 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/ssh/agent/client.go b/ssh/agent/client.go index 37525e1a18..b357e18b0a 100644 --- a/ssh/agent/client.go +++ b/ssh/agent/client.go @@ -430,8 +430,9 @@ func (c *client) List() ([]*Key, error) { return keys, nil case *failureAgentMsg: return nil, errors.New("agent: failed to list keys") + default: + return nil, fmt.Errorf("agent: failed to list keys, unexpected message type %T", msg) } - panic("unreachable") } // Sign has the agent sign the data using a protocol 2 key as defined @@ -462,8 +463,9 @@ func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFl return &sig, nil case *failureAgentMsg: return nil, errors.New("agent: failed to sign challenge") + default: + return nil, fmt.Errorf("agent: failed to sign challenge, unexpected message type %T", msg) } - panic("unreachable") } // unmarshal parses an agent message in packet, returning the parsed diff --git a/ssh/agent/client_test.go b/ssh/agent/client_test.go index f0ffd59592..0fd284d786 100644 --- a/ssh/agent/client_test.go +++ b/ssh/agent/client_test.go @@ -7,6 +7,7 @@ package agent import ( "bytes" "crypto/rand" + "encoding/binary" "errors" "io" "net" @@ -347,6 +348,53 @@ func TestServerResponseTooLarge(t *testing.T) { } } +func TestInvalidResponses(t *testing.T) { + a, b, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + done := make(chan struct{}) + defer func() { <-done }() + + defer a.Close() + defer b.Close() + + agent := NewClient(a) + go func() { + defer close(done) + + resp := []byte{agentSuccess} + msg := make([]byte, 4+len(resp)) + binary.BigEndian.PutUint32(msg[:4], uint32(len(resp))) + copy(msg[4:], resp) + + if _, err := b.Write(msg); err != nil { + t.Errorf("unexpected error sending agent reply: %v", err) + b.Close() + return + } + + if _, err := b.Write(msg); err != nil { + t.Errorf("unexpected error sending agent reply: %v", err) + b.Close() + } + }() + _, err = agent.List() + if err == nil { + t.Fatal("error expected") + } + if !strings.Contains(err.Error(), "failed to list keys, unexpected message type") { + t.Fatalf("unexpected error: %v", err) + } + _, err = agent.Sign(testPublicKeys["rsa"], []byte("message")) + if err == nil { + t.Fatal("error expected") + } + if !strings.Contains(err.Error(), "failed to sign challenge, unexpected message type") { + t.Fatalf("unexpected error: %v", err) + } +} + func TestAuth(t *testing.T) { agent, _, cleanup := startOpenSSHAgent(t) defer cleanup() From 8c9ba318361080ea198c7461b6db621022d0a88e Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sun, 7 Sep 2025 15:18:22 +0200 Subject: [PATCH 15/37] all: freeze and deprecate more packages Fixes golang/go#65250 Change-Id: I6a6a6964a2c87e529be50dd67fec462483b07b75 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/701535 Reviewed-by: Mark Freeman Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- curve25519/curve25519.go | 11 +++++++---- ed25519/ed25519.go | 11 +++++++---- nacl/auth/auth.go | 29 ++++++++++------------------- nacl/sign/sign.go | 21 ++++++++------------- otr/otr.go | 4 ++++ pkcs12/pkcs12.go | 14 +++++++++----- salsa20/salsa/hsalsa20.go | 4 ++++ ssh/test/doc.go | 2 ++ xts/xts.go | 4 ++++ 9 files changed, 55 insertions(+), 45 deletions(-) diff --git a/curve25519/curve25519.go b/curve25519/curve25519.go index 8ff087df4c..048faef3a5 100644 --- a/curve25519/curve25519.go +++ b/curve25519/curve25519.go @@ -3,11 +3,14 @@ // license that can be found in the LICENSE file. // Package curve25519 provides an implementation of the X25519 function, which -// performs scalar multiplication on the elliptic curve known as Curve25519. -// See RFC 7748. +// performs scalar multiplication on the elliptic curve known as Curve25519 +// according to [RFC 7748]. // -// This package is a wrapper for the X25519 implementation -// in the crypto/ecdh package. +// The curve25519 package is a wrapper for the X25519 implementation in the +// crypto/ecdh package. It is [frozen] and is not accepting new features. +// +// [RFC 7748]: https://datatracker.ietf.org/doc/html/rfc7748 +// [frozen]: https://go.dev/wiki/Frozen package curve25519 import "crypto/ecdh" diff --git a/ed25519/ed25519.go b/ed25519/ed25519.go index 59b3a95a7d..df453dcce0 100644 --- a/ed25519/ed25519.go +++ b/ed25519/ed25519.go @@ -2,16 +2,19 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package ed25519 implements the Ed25519 signature algorithm. See -// https://ed25519.cr.yp.to/. +// Package ed25519 implements the Ed25519 signature algorithm. // // These functions are also compatible with the “Ed25519” function defined in -// RFC 8032. However, unlike RFC 8032's formulation, this package's private key +// [RFC 8032]. However, unlike RFC 8032's formulation, this package's private key // representation includes a public key suffix to make multiple signing // operations with the same key more efficient. This package refers to the RFC // 8032 private key as the “seed”. // -// This package is a wrapper around the standard library crypto/ed25519 package. +// The ed25519 package is a wrapper for the Ed25519 implementation in the +// crypto/ed25519 package. It is [frozen] and is not accepting new features. +// +// [RFC 8032]: https://datatracker.ietf.org/doc/html/rfc8032 +// [frozen]: https://go.dev/wiki/Frozen package ed25519 import ( diff --git a/nacl/auth/auth.go b/nacl/auth/auth.go index 1d588d5c1c..136093841f 100644 --- a/nacl/auth/auth.go +++ b/nacl/auth/auth.go @@ -2,25 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -/* -Package auth authenticates a message using a secret key. - -The Sum function, viewed as a function of the message for a uniform random -key, is designed to meet the standard notion of unforgeability. This means -that an attacker cannot find authenticators for any messages not authenticated -by the sender, even if the attacker has adaptively influenced the messages -authenticated by the sender. For a formal definition see, e.g., Section 2.4 -of Bellare, Kilian, and Rogaway, "The security of the cipher block chaining -message authentication code," Journal of Computer and System Sciences 61 (2000), -362–399; http://www-cse.ucsd.edu/~mihir/papers/cbc.html. - -auth does not make any promises regarding "strong" unforgeability; perhaps -one valid authenticator can be converted into another valid authenticator for -the same message. NaCl also does not make any promises regarding "truncated -unforgeability." - -This package is interoperable with NaCl: https://nacl.cr.yp.to/auth.html. -*/ +// Package auth authenticates a message using a secret key. +// +// This package is interoperable with [NaCl]. +// +// The auth package is essentially a wrapper for HMAC-SHA-512 (implemented by +// crypto/hmac and crypto/sha512), truncated to 32 bytes. It is [frozen] and is +// not accepting new features. +// +// [NaCl]: https://nacl.cr.yp.to/auth.html +// [frozen]: https://go.dev/wiki/Frozen package auth import ( diff --git a/nacl/sign/sign.go b/nacl/sign/sign.go index 109c08bb95..1cf2c4be2c 100644 --- a/nacl/sign/sign.go +++ b/nacl/sign/sign.go @@ -4,20 +4,15 @@ // Package sign signs small messages using public-key cryptography. // -// Sign uses Ed25519 to sign messages. The length of messages is not hidden. -// Messages should be small because: -// 1. The whole message needs to be held in memory to be processed. -// 2. Using large messages pressures implementations on small machines to process -// plaintext without verifying the signature. This is very dangerous, and this API -// discourages it, but a protocol that uses excessive message sizes might present -// some implementations with no other choice. -// 3. Performance may be improved by working with messages that fit into data caches. -// Thus large amounts of data should be chunked so that each message is small. +// This package is interoperable with [libsodium], as well as [TweetNaCl]. // -// This package is not interoperable with the current release of NaCl -// (https://nacl.cr.yp.to/sign.html), which does not support Ed25519 yet. However, -// it is compatible with the NaCl fork libsodium (https://www.libsodium.org), as well -// as TweetNaCl (https://tweetnacl.cr.yp.to/). +// The sign package is essentially a wrapper for the Ed25519 signature +// algorithm (implemented by crypto/ed25519). It is [frozen] and is not accepting +// new features. +// +// [libsodium]: https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures +// [TweetNaCl]: https://tweetnacl.cr.yp.to/ +// [frozen]: https://go.dev/wiki/Frozen package sign import ( diff --git a/otr/otr.go b/otr/otr.go index 6210c1ae61..a36f7ca245 100644 --- a/otr/otr.go +++ b/otr/otr.go @@ -8,6 +8,10 @@ // The version of OTR implemented by this package has been deprecated // (https://bugs.otr.im/lib/libotr/issues/140). An implementation of OTRv3 is // available at https://github.com/coyim/otr3. +// +// The otr package is [frozen] and is not accepting new features. +// +// [frozen]: https://go.dev/wiki/Frozen package otr import ( diff --git a/pkcs12/pkcs12.go b/pkcs12/pkcs12.go index 3a89bdb3e3..374d9facf8 100644 --- a/pkcs12/pkcs12.go +++ b/pkcs12/pkcs12.go @@ -4,12 +4,16 @@ // Package pkcs12 implements some of PKCS#12. // -// This implementation is distilled from https://tools.ietf.org/html/rfc7292 -// and referenced documents. It is intended for decoding P12/PFX-stored -// certificates and keys for use with the crypto/tls package. +// This implementation is distilled from [RFC 7292] and referenced documents. +// It is intended for decoding P12/PFX-stored certificates and keys for use +// with the crypto/tls package. // -// This package is frozen. If it's missing functionality you need, consider -// an alternative like software.sslmate.com/src/go-pkcs12. +// The pkcs12 package is [frozen] and is not accepting new features. +// If it's missing functionality you need, consider an alternative like +// software.sslmate.com/src/go-pkcs12. +// +// [RFC 7292]: https://datatracker.ietf.org/doc/html/rfc7292 +// [frozen]: https://go.dev/wiki/Frozen package pkcs12 import ( diff --git a/salsa20/salsa/hsalsa20.go b/salsa20/salsa/hsalsa20.go index 3685b34458..75df77406d 100644 --- a/salsa20/salsa/hsalsa20.go +++ b/salsa20/salsa/hsalsa20.go @@ -3,6 +3,10 @@ // license that can be found in the LICENSE file. // Package salsa provides low-level access to functions in the Salsa family. +// +// Deprecated: this package exposes unsafe low-level operations. New applications +// should consider using the AEAD construction in golang.org/x/crypto/chacha20poly1305 +// instead. Existing users should migrate to golang.org/x/crypto/salsa20. package salsa import "math/bits" diff --git a/ssh/test/doc.go b/ssh/test/doc.go index 444b29966b..865781c819 100644 --- a/ssh/test/doc.go +++ b/ssh/test/doc.go @@ -4,4 +4,6 @@ // Package test contains integration tests for the // golang.org/x/crypto/ssh package. +// +// Deprecated: this package is for internal use only. package test diff --git a/xts/xts.go b/xts/xts.go index d64f536f9d..6a73020207 100644 --- a/xts/xts.go +++ b/xts/xts.go @@ -21,6 +21,10 @@ // // Note that XTS is usually not appropriate for any use besides disk encryption. // Most users should use an AEAD mode like GCM (from crypto/cipher.NewGCM) instead. +// +// The xts package is [frozen] and is not accepting new features. +// +// [frozen]: https://go.dev/wiki/Frozen package xts import ( From 96dc232fbd7928e9c23da42e770c8b79a2348d86 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 10 Jul 2025 10:58:35 +0200 Subject: [PATCH 16/37] x509roots/fallback/bundle: add bundle package to export root certs Fixes golang/go#69898 Change-Id: Idbb1bbe48016a622414c84a56fe26f48bfe712c8 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/687155 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Auto-Submit: Roland Shoemaker Reviewed-by: Mateusz Poliwczak --- x509roots/fallback/{ => bundle}/bundle.der | Bin x509roots/fallback/{ => bundle}/bundle.go | 2 +- .../fallback/{ => bundle}/bundle_test.go | 2 +- x509roots/fallback/bundle/roots.go | 73 ++++++++++++++++++ x509roots/fallback/bundle/roots_test.go | 18 +++++ x509roots/fallback/fallback.go | 68 +++------------- x509roots/gen_fallback_bundle.go | 6 +- 7 files changed, 105 insertions(+), 64 deletions(-) rename x509roots/fallback/{ => bundle}/bundle.der (100%) rename x509roots/fallback/{ => bundle}/bundle.go (99%) rename x509roots/fallback/{ => bundle}/bundle_test.go (98%) create mode 100644 x509roots/fallback/bundle/roots.go create mode 100644 x509roots/fallback/bundle/roots_test.go diff --git a/x509roots/fallback/bundle.der b/x509roots/fallback/bundle/bundle.der similarity index 100% rename from x509roots/fallback/bundle.der rename to x509roots/fallback/bundle/bundle.der diff --git a/x509roots/fallback/bundle.go b/x509roots/fallback/bundle/bundle.go similarity index 99% rename from x509roots/fallback/bundle.go rename to x509roots/fallback/bundle/bundle.go index ee99a40a28..be9e857790 100644 --- a/x509roots/fallback/bundle.go +++ b/x509roots/fallback/bundle/bundle.go @@ -1,6 +1,6 @@ // Code generated by gen_fallback_bundle.go; DO NOT EDIT. -package fallback +package bundle var unparsedCertificates = []unparsedCertificate{ { diff --git a/x509roots/fallback/bundle_test.go b/x509roots/fallback/bundle/bundle_test.go similarity index 98% rename from x509roots/fallback/bundle_test.go rename to x509roots/fallback/bundle/bundle_test.go index a8922cc93d..3eafe153af 100644 --- a/x509roots/fallback/bundle_test.go +++ b/x509roots/fallback/bundle/bundle_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package fallback +package bundle import ( "crypto/sha256" diff --git a/x509roots/fallback/bundle/roots.go b/x509roots/fallback/bundle/roots.go new file mode 100644 index 0000000000..38a1b3d671 --- /dev/null +++ b/x509roots/fallback/bundle/roots.go @@ -0,0 +1,73 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bundle contains the bundle of root certificates parsed from the NSS +// trust store, using x509roots/nss. +package bundle + +import ( + "crypto/x509" + _ "embed" + "fmt" + "iter" + "time" +) + +//go:embed bundle.der +var rawCerts []byte + +// Root represents a root certificate parsed from the NSS trust store. +type Root struct { + // Certificate is the DER-encoded certificate (read-only; do not modify!). + Certificate []byte + + // Constraint is nil if the root is unconstrained. If Constraint is non-nil, + // the certificate has additional constraints that cannot be encoded in + // X.509, and when building a certificate chain anchored with this root the + // chain should be passed to this function to check its validity. If using a + // [crypto/x509.CertPool] the root should be added using + // [crypto/x509.CertPool.AddCertWithConstraint]. + Constraint func([]*x509.Certificate) error +} + +// Roots returns the bundle of root certificates from the NSS trust store. The +// [Root.Certificate] slice must be treated as read-only and should not be +// modified. +func Roots() iter.Seq[Root] { + return func(yield func(Root) bool) { + for _, unparsed := range unparsedCertificates { + root := Root{ + Certificate: rawCerts[unparsed.certStartOff : unparsed.certStartOff+unparsed.certLength], + } + // parse possible constraints, this should check all fields of unparsedCertificate. + if unparsed.distrustAfter != "" { + distrustAfter, err := time.Parse(time.RFC3339, unparsed.distrustAfter) + if err != nil { + panic(fmt.Sprintf("failed to parse distrustAfter %q: %s", unparsed.distrustAfter, err)) + } + root.Constraint = func(chain []*x509.Certificate) error { + for _, c := range chain { + if c.NotBefore.After(distrustAfter) { + return fmt.Errorf("certificate issued after distrust-after date %q", distrustAfter) + } + } + return nil + } + } + if !yield(root) { + return + } + } + } +} + +type unparsedCertificate struct { + cn string + sha256Hash string + certStartOff int + certLength int + + // possible constraints + distrustAfter string +} diff --git a/x509roots/fallback/bundle/roots_test.go b/x509roots/fallback/bundle/roots_test.go new file mode 100644 index 0000000000..04ba9db299 --- /dev/null +++ b/x509roots/fallback/bundle/roots_test.go @@ -0,0 +1,18 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bundle + +import ( + "crypto/x509" + "testing" +) + +func TestRootsCanBeParsed(t *testing.T) { + for root := range Roots() { + if _, err := x509.ParseCertificate(root.Certificate); err != nil { + t.Fatalf("Could not parse root certificate: %v", err) + } + } +} diff --git a/x509roots/fallback/fallback.go b/x509roots/fallback/fallback.go index a0dad330ea..79e18704a8 100644 --- a/x509roots/fallback/fallback.go +++ b/x509roots/fallback/fallback.go @@ -20,13 +20,9 @@ package fallback import ( "crypto/x509" - _ "embed" - "fmt" - "time" -) -//go:embed bundle.der -var rawCerts []byte + "golang.org/x/crypto/x509roots/fallback/bundle" +) func init() { x509.SetFallbackRoots(newFallbackCertPool()) @@ -34,62 +30,16 @@ func init() { func newFallbackCertPool() *x509.CertPool { p := x509.NewCertPool() - for _, c := range mustParse(unparsedCertificates) { - if len(c.constraints) == 0 { - p.AddCert(c.cert) - } else { - p.AddCertWithConstraint(c.cert, func(chain []*x509.Certificate) error { - for _, constraint := range c.constraints { - if err := constraint(chain); err != nil { - return err - } - } - return nil - }) - } - } - return p -} - -type unparsedCertificate struct { - cn string - sha256Hash string - certStartOff int - certLength int - - // possible constraints - distrustAfter string -} - -type parsedCertificate struct { - cert *x509.Certificate - constraints []func([]*x509.Certificate) error -} - -func mustParse(unparsedCerts []unparsedCertificate) []parsedCertificate { - b := make([]parsedCertificate, 0, len(unparsedCerts)) - for _, unparsed := range unparsedCerts { - cert, err := x509.ParseCertificate(rawCerts[unparsed.certStartOff : unparsed.certStartOff+unparsed.certLength]) + for c := range bundle.Roots() { + cert, err := x509.ParseCertificate(c.Certificate) if err != nil { panic(err) } - parsed := parsedCertificate{cert: cert} - // parse possible constraints, this should check all fields of unparsedCertificate. - if unparsed.distrustAfter != "" { - distrustAfter, err := time.Parse(time.RFC3339, unparsed.distrustAfter) - if err != nil { - panic(fmt.Sprintf("failed to parse distrustAfter %q: %s", unparsed.distrustAfter, err)) - } - parsed.constraints = append(parsed.constraints, func(chain []*x509.Certificate) error { - for _, c := range chain { - if c.NotBefore.After(distrustAfter) { - return fmt.Errorf("certificate issued after distrust-after date %q", distrustAfter) - } - } - return nil - }) + if c.Constraint == nil { + p.AddCert(cert) + } else { + p.AddCertWithConstraint(cert, c.Constraint) } - b = append(b, parsed) } - return b + return p } diff --git a/x509roots/gen_fallback_bundle.go b/x509roots/gen_fallback_bundle.go index ed2f9f84fb..810996cbac 100644 --- a/x509roots/gen_fallback_bundle.go +++ b/x509roots/gen_fallback_bundle.go @@ -27,7 +27,7 @@ import ( const tmpl = `// Code generated by gen_fallback_bundle.go; DO NOT EDIT. -package fallback +package bundle var unparsedCertificates = []unparsedCertificate{ ` @@ -35,8 +35,8 @@ var unparsedCertificates = []unparsedCertificate{ var ( certDataURL = flag.String("certdata-url", "https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt", "URL to the raw certdata.txt file to parse (certdata-path overrides this, if provided)") certDataPath = flag.String("certdata-path", "", "Path to the NSS certdata.txt file to parse (this overrides certdata-url, if provided)") - output = flag.String("output", "fallback/bundle.go", "Path to file to write output to") - derOutput = flag.String("deroutput", "fallback/bundle.der", "Path to file to write output to (DER certificate bundle)") + output = flag.String("output", "fallback/bundle/bundle.go", "Path to file to write output to") + derOutput = flag.String("deroutput", "fallback/bundle/bundle.der", "Path to file to write output to (DER certificate bundle)") ) func main() { From f4d47b0db5875e61dd52acdb63be800177ab48bb Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Tue, 12 Aug 2025 07:59:34 +0200 Subject: [PATCH 17/37] ssh: return clearer error when signature algorithm is used as key format ParsePublicKey now returns a more specific error when a signature algorithm like rsa-sha2-256 is mistakenly provided as a key format Change-Id: Ic08286a5b2b326e99dd3e61594919203f0c36791 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/695075 Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Mark Freeman Reviewed-by: Michael Knyszek --- ssh/common.go | 29 +++++++++++++++++++++++++++++ ssh/common_test.go | 20 ++++++++++++++++++++ ssh/keys.go | 18 ++++++++++++++++-- ssh/keys_test.go | 11 +++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/ssh/common.go b/ssh/common.go index 8bfad16c41..36c82a73ac 100644 --- a/ssh/common.go +++ b/ssh/common.go @@ -312,6 +312,35 @@ func algorithmsForKeyFormat(keyFormat string) []string { } } +// keyFormatForAlgorithm returns the key format corresponding to the given +// signature algorithm. It returns an empty string if the signature algorithm is +// invalid or unsupported. +func keyFormatForAlgorithm(sigAlgo string) string { + switch sigAlgo { + case KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512: + return KeyAlgoRSA + case CertAlgoRSAv01, CertAlgoRSASHA256v01, CertAlgoRSASHA512v01: + return CertAlgoRSAv01 + case KeyAlgoED25519, + KeyAlgoSKED25519, + KeyAlgoSKECDSA256, + KeyAlgoECDSA256, + KeyAlgoECDSA384, + KeyAlgoECDSA521, + InsecureKeyAlgoDSA, + InsecureCertAlgoDSAv01, + CertAlgoECDSA256v01, + CertAlgoECDSA384v01, + CertAlgoECDSA521v01, + CertAlgoSKECDSA256v01, + CertAlgoED25519v01, + CertAlgoSKED25519v01: + return sigAlgo + default: + return "" + } +} + // isRSA returns whether algo is a supported RSA algorithm, including certificate // algorithms. func isRSA(algo string) bool { diff --git a/ssh/common_test.go b/ssh/common_test.go index 67cf1f4269..80aa2df73b 100644 --- a/ssh/common_test.go +++ b/ssh/common_test.go @@ -5,7 +5,9 @@ package ssh import ( + "maps" "reflect" + "slices" "testing" ) @@ -174,3 +176,21 @@ func TestFindAgreedAlgorithms(t *testing.T) { }) } } + +func TestKeyFormatAlgorithms(t *testing.T) { + supportedAlgos := SupportedAlgorithms() + insecureAlgos := InsecureAlgorithms() + algoritms := append(supportedAlgos.PublicKeyAuths, insecureAlgos.PublicKeyAuths...) + algoritms = append(algoritms, slices.Collect(maps.Keys(certKeyAlgoNames))...) + + for _, algo := range algoritms { + keyFormat := keyFormatForAlgorithm(algo) + if keyFormat == "" { + t.Errorf("got empty key format for algorithm %q", algo) + } + if !slices.Contains(algorithmsForKeyFormat(keyFormat), algo) { + t.Errorf("algorithms for key format %q, does not contain %q", keyFormat, algo) + } + + } +} diff --git a/ssh/keys.go b/ssh/keys.go index a28c0de503..8327260526 100644 --- a/ssh/keys.go +++ b/ssh/keys.go @@ -89,6 +89,11 @@ func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err err } return cert, nil, nil } + if keyFormat := keyFormatForAlgorithm(algo); keyFormat != "" { + return nil, nil, fmt.Errorf("ssh: signature algorithm %q isn't a key format; key is malformed and should be re-encoded with type %q", + algo, keyFormat) + } + return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo) } @@ -191,9 +196,10 @@ func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey return "", nil, nil, "", nil, io.EOF } -// ParseAuthorizedKey parses a public key from an authorized_keys -// file used in OpenSSH according to the sshd(8) manual page. +// ParseAuthorizedKey parses a public key from an authorized_keys file used in +// OpenSSH according to the sshd(8) manual page. Invalid lines are ignored. func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { + var lastErr error for len(in) > 0 { end := bytes.IndexByte(in, '\n') if end != -1 { @@ -222,6 +228,8 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { return out, comment, options, rest, nil + } else { + lastErr = err } // No key type recognised. Maybe there's an options field at @@ -264,12 +272,18 @@ func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []str if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { options = candidateOptions return out, comment, options, rest, nil + } else { + lastErr = err } in = rest continue } + if lastErr != nil { + return nil, "", nil, nil, fmt.Errorf("ssh: no key found; last parsing error for ignored line: %w", lastErr) + } + return nil, "", nil, nil, errors.New("ssh: no key found") } diff --git a/ssh/keys_test.go b/ssh/keys_test.go index f3eb223a9c..661e3cb31c 100644 --- a/ssh/keys_test.go +++ b/ssh/keys_test.go @@ -59,6 +59,17 @@ func TestKeyMarshalParse(t *testing.T) { } } +func TestParsePublicKeyWithSigningAlgoAsKeyFormat(t *testing.T) { + key := []byte(`rsa-sha2-256 AAAADHJzYS1zaGEyLTI1NgAAAAMBAAEAAAEBAJ7qMyjLXEJCCJmRknuCLo0uPi5GrPY5pQYr84lhlN8Gor5KVL2LKYCW4e70r5xzj7SrHHSCft1FMlYg1KDO9xrprJh733kQqAPWETmSuH0EfRtGtcH6EarKyVxk6As076/yNiiMKVBtG0RPa1L7FviTfcYK4vnCCVrbv3RmA5CCzuG5BSMbRLxzVb4Ri3p8jhxYT8N4QGe/2yqvJLys5vQ9szpZR3tcFp3DJIVZhBRfR6LnoY23XZniAAMQaUVBX86dXQ++dNwAwZSXSt9Og+AniOCiBYqhNVa5n3DID/H7YtEtG+CbZr3r2KD3fv8AfSLRar4XOp8rsRdD31h/kr8=`) + _, _, _, _, err := ParseAuthorizedKey(key) + if err == nil { + t.Fatal("parsing a public key using a signature algorithm as the key format succeeded unexpectedly") + } + if !strings.Contains(err.Error(), `signature algorithm "rsa-sha2-256" isn't a key format`) { + t.Errorf(`got %v, expected 'signature algorithm "rsa-sha2-256" isn't a key format'`, err) + } +} + func TestUnsupportedCurves(t *testing.T) { raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) if err != nil { From ddb4e80c6ad38c8a94001924a6ff8424f5cae369 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 14 Sep 2025 15:28:12 +0200 Subject: [PATCH 18/37] ssh: remove custom contains, use slices.Contains Change-Id: If4784469e7285675bdd51399a76bdc16f0036a2e Reviewed-on: https://go-review.googlesource.com/c/crypto/+/703635 Reviewed-by: Mark Freeman Reviewed-by: Sean Liao Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- ssh/client_auth.go | 24 ++++++++---------------- ssh/client_auth_test.go | 3 ++- ssh/common.go | 4 ++-- ssh/handshake.go | 9 +++++---- ssh/keys.go | 9 +++++---- ssh/server.go | 9 +++++---- 6 files changed, 27 insertions(+), 31 deletions(-) diff --git a/ssh/client_auth.go b/ssh/client_auth.go index c12818fdc5..3127e49903 100644 --- a/ssh/client_auth.go +++ b/ssh/client_auth.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "io" + "slices" "strings" ) @@ -83,7 +84,7 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error { // success return nil } else if ok == authFailure { - if m := auth.method(); !contains(tried, m) { + if m := auth.method(); !slices.Contains(tried, m) { tried = append(tried, m) } } @@ -97,7 +98,7 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error { findNext: for _, a := range config.Auth { candidateMethod := a.method() - if contains(tried, candidateMethod) { + if slices.Contains(tried, candidateMethod) { continue } for _, meth := range methods { @@ -117,15 +118,6 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error { return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried) } -func contains(list []string, e string) bool { - for _, s := range list { - if s == e { - return true - } - } - return false -} - // An AuthMethod represents an instance of an RFC 4252 authentication method. type AuthMethod interface { // auth authenticates user over transport t. @@ -255,7 +247,7 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiA // Fallback to use if there is no "server-sig-algs" extension or a // common algorithm cannot be found. We use the public key format if the // MultiAlgorithmSigner supports it, otherwise we return an error. - if !contains(as.Algorithms(), underlyingAlgo(keyFormat)) { + if !slices.Contains(as.Algorithms(), underlyingAlgo(keyFormat)) { return "", fmt.Errorf("ssh: no common public key signature algorithm, server only supports %q for key type %q, signer only supports %v", underlyingAlgo(keyFormat), keyFormat, as.Algorithms()) } @@ -284,7 +276,7 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiA // Filter algorithms based on those supported by MultiAlgorithmSigner. var keyAlgos []string for _, algo := range algorithmsForKeyFormat(keyFormat) { - if contains(as.Algorithms(), underlyingAlgo(algo)) { + if slices.Contains(as.Algorithms(), underlyingAlgo(algo)) { keyAlgos = append(keyAlgos, algo) } } @@ -334,7 +326,7 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand // the key try to use the obtained algorithm as if "server-sig-algs" had // not been implemented if supported from the algorithm signer. if !ok && idx < origSignersLen && isRSACert(algo) && algo != CertAlgoRSAv01 { - if contains(as.Algorithms(), KeyAlgoRSA) { + if slices.Contains(as.Algorithms(), KeyAlgoRSA) { // We retry using the compat algorithm after all signers have // been tried normally. signers = append(signers, &multiAlgorithmSigner{ @@ -385,7 +377,7 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand // contain the "publickey" method, do not attempt to authenticate with any // other keys. According to RFC 4252 Section 7, the latter can occur when // additional authentication methods are required. - if success == authSuccess || !contains(methods, cb.method()) { + if success == authSuccess || !slices.Contains(methods, cb.method()) { return success, methods, err } } @@ -434,7 +426,7 @@ func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { // servers send the key type instead. OpenSSH allows any algorithm // that matches the public key, so we do the same. // https://github.com/openssh/openssh-portable/blob/86bdd385/sshconnect2.c#L709 - if !contains(algorithmsForKeyFormat(key.Type()), msg.Algo) { + if !slices.Contains(algorithmsForKeyFormat(key.Type()), msg.Algo) { return false, nil } if !bytes.Equal(msg.PubKey, pubKey) { diff --git a/ssh/client_auth_test.go b/ssh/client_auth_test.go index 8d1767cdb7..e398c4062c 100644 --- a/ssh/client_auth_test.go +++ b/ssh/client_auth_test.go @@ -14,6 +14,7 @@ import ( "net" "os" "runtime" + "slices" "strings" "testing" ) @@ -1214,7 +1215,7 @@ func (cb configurablePublicKeyCallback) auth(session []byte, user string, c pack if err != nil { return authFailure, nil, err } - if success == authSuccess || !contains(methods, cb.method()) { + if success == authSuccess || !slices.Contains(methods, cb.method()) { return success, methods, err } diff --git a/ssh/common.go b/ssh/common.go index 36c82a73ac..b1884c2c04 100644 --- a/ssh/common.go +++ b/ssh/common.go @@ -345,7 +345,7 @@ func keyFormatForAlgorithm(sigAlgo string) string { // algorithms. func isRSA(algo string) bool { algos := algorithmsForKeyFormat(KeyAlgoRSA) - return contains(algos, underlyingAlgo(algo)) + return slices.Contains(algos, underlyingAlgo(algo)) } func isRSACert(algo string) bool { @@ -544,7 +544,7 @@ func (c *Config) SetDefaults() { if kexAlgoMap[k] != nil { // Ignore the KEX if we have no kexAlgoMap definition. kexs = append(kexs, k) - if k == KeyExchangeCurve25519 && !contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) { + if k == KeyExchangeCurve25519 && !slices.Contains(c.KeyExchanges, keyExchangeCurve25519LibSSH) { kexs = append(kexs, keyExchangeCurve25519LibSSH) } } diff --git a/ssh/handshake.go b/ssh/handshake.go index a90bfe331c..4be3cbb6de 100644 --- a/ssh/handshake.go +++ b/ssh/handshake.go @@ -10,6 +10,7 @@ import ( "io" "log" "net" + "slices" "strings" "sync" ) @@ -527,7 +528,7 @@ func (t *handshakeTransport) sendKexInit() error { switch s := k.(type) { case MultiAlgorithmSigner: for _, algo := range algorithmsForKeyFormat(keyFormat) { - if contains(s.Algorithms(), underlyingAlgo(algo)) { + if slices.Contains(s.Algorithms(), underlyingAlgo(algo)) { msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo) } } @@ -679,7 +680,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { return err } - if t.sessionID == nil && ((isClient && contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && contains(clientInit.KexAlgos, kexStrictClient))) { + if t.sessionID == nil && ((isClient && slices.Contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && slices.Contains(clientInit.KexAlgos, kexStrictClient))) { t.strictMode = true if err := t.conn.setStrictMode(); err != nil { return err @@ -736,7 +737,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { // On the server side, after the first SSH_MSG_NEWKEYS, send a SSH_MSG_EXT_INFO // message with the server-sig-algs extension if the client supports it. See // RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9. - if !isClient && firstKeyExchange && contains(clientInit.KexAlgos, "ext-info-c") { + if !isClient && firstKeyExchange && slices.Contains(clientInit.KexAlgos, "ext-info-c") { supportedPubKeyAuthAlgosList := strings.Join(t.publicKeyAuthAlgorithms, ",") extInfo := &extInfoMsg{ NumExtensions: 2, @@ -790,7 +791,7 @@ func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, a func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner { for _, k := range hostKeys { if s, ok := k.(MultiAlgorithmSigner); ok { - if !contains(s.Algorithms(), underlyingAlgo(algo)) { + if !slices.Contains(s.Algorithms(), underlyingAlgo(algo)) { continue } } diff --git a/ssh/keys.go b/ssh/keys.go index 8327260526..c972169773 100644 --- a/ssh/keys.go +++ b/ssh/keys.go @@ -27,6 +27,7 @@ import ( "fmt" "io" "math/big" + "slices" "strings" "golang.org/x/crypto/ssh/internal/bcrypt_pbkdf" @@ -409,11 +410,11 @@ func NewSignerWithAlgorithms(signer AlgorithmSigner, algorithms []string) (Multi } for _, algo := range algorithms { - if !contains(supportedAlgos, algo) { + if !slices.Contains(supportedAlgos, algo) { return nil, fmt.Errorf("ssh: algorithm %q is not supported for key type %q", algo, signer.PublicKey().Type()) } - if !contains(signerAlgos, algo) { + if !slices.Contains(signerAlgos, algo) { return nil, fmt.Errorf("ssh: algorithm %q is restricted for the provided signer", algo) } } @@ -500,7 +501,7 @@ func (r *rsaPublicKey) Marshal() []byte { func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { supportedAlgos := algorithmsForKeyFormat(r.Type()) - if !contains(supportedAlgos, sig.Format) { + if !slices.Contains(supportedAlgos, sig.Format) { return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) } hash := hashFuncs[sig.Format] @@ -1126,7 +1127,7 @@ func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm algorithm = s.pubKey.Type() } - if !contains(s.Algorithms(), algorithm) { + if !slices.Contains(s.Algorithms(), algorithm) { return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type()) } diff --git a/ssh/server.go b/ssh/server.go index 98679ba5b6..f06c08cd46 100644 --- a/ssh/server.go +++ b/ssh/server.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "net" + "slices" "strings" ) @@ -246,7 +247,7 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha fullConf.PublicKeyAuthAlgorithms = defaultPubKeyAuthAlgos } else { for _, algo := range fullConf.PublicKeyAuthAlgorithms { - if !contains(SupportedAlgorithms().PublicKeyAuths, algo) && !contains(InsecureAlgorithms().PublicKeyAuths, algo) { + if !slices.Contains(SupportedAlgorithms().PublicKeyAuths, algo) && !slices.Contains(InsecureAlgorithms().PublicKeyAuths, algo) { c.Close() return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo) } @@ -631,7 +632,7 @@ userAuthLoop: return nil, parseError(msgUserAuthRequest) } algo := string(algoBytes) - if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) { + if !slices.Contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) { authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) break } @@ -695,7 +696,7 @@ userAuthLoop: // ssh-rsa-cert-v01@openssh.com algorithm with ssh-rsa public // key type. The algorithm and public key type must be // consistent: both must be certificate algorithms, or neither. - if !contains(algorithmsForKeyFormat(pubKey.Type()), algo) { + if !slices.Contains(algorithmsForKeyFormat(pubKey.Type()), algo) { authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q", pubKey.Type(), algo) break @@ -705,7 +706,7 @@ userAuthLoop: // algorithm name that corresponds to algo with // sig.Format. This is usually the same, but // for certs, the names differ. - if !contains(config.PublicKeyAuthAlgorithms, sig.Format) { + if !slices.Contains(config.PublicKeyAuthAlgorithms, sig.Format) { authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) break } From 66c3d8ce714c31eb5a8adb6c931b4e29f5bebcf5 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 24 Aug 2025 15:55:24 +0200 Subject: [PATCH 19/37] ssh: add support for FIPS mode Unsupported algoritms are silently ignored and not negotiated, or rejected Fixes golang/go#75061 Change-Id: I08d50d10a97c08e78aedead89ca61beceff88918 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/698795 Reviewed-by: Mio Mio Reviewed-by: Junyang Shao Reviewed-by: Filippo Valsorda Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- ssh/certs_test.go | 4 ++- ssh/cipher.go | 62 ++++++++++++++++++++++++----------------------- ssh/common.go | 50 ++++++++++++++++++++++++++------------ ssh/doc.go | 10 ++++++++ ssh/kex.go | 24 +++++++++++++++--- ssh/keys.go | 42 +++++++++++++++++++++++++------- ssh/mac.go | 42 ++++++++++++++++++++++---------- ssh/transport.go | 4 +++ 8 files changed, 166 insertions(+), 72 deletions(-) diff --git a/ssh/certs_test.go b/ssh/certs_test.go index e2a6fedc8b..ba435ab9cf 100644 --- a/ssh/certs_test.go +++ b/ssh/certs_test.go @@ -338,7 +338,9 @@ func TestCertTypes(t *testing.T) { CertType: UserCert, Key: priv.PublicKey(), } - cert.SignCert(rand.Reader, priv) + if err := cert.SignCert(rand.Reader, priv); err != nil { + t.Fatalf("error signing certificate: %v", err) + } certSigner, err := NewCertSigner(cert, priv) if err != nil { diff --git a/ssh/cipher.go b/ssh/cipher.go index 6a5b582aa9..7554ed57a9 100644 --- a/ssh/cipher.go +++ b/ssh/cipher.go @@ -8,6 +8,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/des" + "crypto/fips140" "crypto/rc4" "crypto/subtle" "encoding/binary" @@ -15,6 +16,7 @@ import ( "fmt" "hash" "io" + "slices" "golang.org/x/crypto/chacha20" "golang.org/x/crypto/internal/poly1305" @@ -93,41 +95,41 @@ func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, } // cipherModes documents properties of supported ciphers. Ciphers not included -// are not supported and will not be negotiated, even if explicitly requested in -// ClientConfig.Crypto.Ciphers. -var cipherModes = map[string]*cipherMode{ - // Ciphers from RFC 4344, which introduced many CTR-based ciphers. Algorithms - // are defined in the order specified in the RFC. - CipherAES128CTR: {16, aes.BlockSize, streamCipherMode(0, newAESCTR)}, - CipherAES192CTR: {24, aes.BlockSize, streamCipherMode(0, newAESCTR)}, - CipherAES256CTR: {32, aes.BlockSize, streamCipherMode(0, newAESCTR)}, - - // Ciphers from RFC 4345, which introduces security-improved arcfour ciphers. - // They are defined in the order specified in the RFC. - InsecureCipherRC4128: {16, 0, streamCipherMode(1536, newRC4)}, - InsecureCipherRC4256: {32, 0, streamCipherMode(1536, newRC4)}, - - // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. - // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and - // RC4) has problems with weak keys, and should be used with caution." - // RFC 4345 introduces improved versions of Arcfour. - InsecureCipherRC4: {16, 0, streamCipherMode(0, newRC4)}, - - // AEAD ciphers - CipherAES128GCM: {16, 12, newGCMCipher}, - CipherAES256GCM: {32, 12, newGCMCipher}, - CipherChaCha20Poly1305: {64, 0, newChaCha20Cipher}, - +// are not supported and will not be negotiated, even if explicitly configured. +// When FIPS mode is enabled, only FIPS-approved algorithms are included. +var cipherModes = map[string]*cipherMode{} + +func init() { + cipherModes[CipherAES128CTR] = &cipherMode{16, aes.BlockSize, streamCipherMode(0, newAESCTR)} + cipherModes[CipherAES192CTR] = &cipherMode{24, aes.BlockSize, streamCipherMode(0, newAESCTR)} + cipherModes[CipherAES256CTR] = &cipherMode{32, aes.BlockSize, streamCipherMode(0, newAESCTR)} + // Use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, + // we'll wire it up to NewGCMForSSH in Go 1.26. + // + // For now it means we'll work with fips140=on but not fips140=only. + cipherModes[CipherAES128GCM] = &cipherMode{16, 12, newGCMCipher} + cipherModes[CipherAES256GCM] = &cipherMode{32, 12, newGCMCipher} + + if fips140.Enabled() { + defaultCiphers = slices.DeleteFunc(defaultCiphers, func(algo string) bool { + _, ok := cipherModes[algo] + return !ok + }) + return + } + + cipherModes[CipherChaCha20Poly1305] = &cipherMode{64, 0, newChaCha20Cipher} + // Insecure ciphers not included in the default configuration. + cipherModes[InsecureCipherRC4128] = &cipherMode{16, 0, streamCipherMode(1536, newRC4)} + cipherModes[InsecureCipherRC4256] = &cipherMode{32, 0, streamCipherMode(1536, newRC4)} + cipherModes[InsecureCipherRC4] = &cipherMode{16, 0, streamCipherMode(0, newRC4)} // CBC mode is insecure and so is not included in the default config. // (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.pdf). If absolutely // needed, it's possible to specify a custom Config to enable it. // You should expect that an active attacker can recover plaintext if // you do. - InsecureCipherAES128CBC: {16, aes.BlockSize, newAESCBCCipher}, - - // 3des-cbc is insecure and is not included in the default - // config. - InsecureCipherTripleDESCBC: {24, des.BlockSize, newTripleDESCBCCipher}, + cipherModes[InsecureCipherAES128CBC] = &cipherMode{16, aes.BlockSize, newAESCBCCipher} + cipherModes[InsecureCipherTripleDESCBC] = &cipherMode{24, des.BlockSize, newTripleDESCBCCipher} } // prefixLen is the length of the packet prefix that contains the packet length diff --git a/ssh/common.go b/ssh/common.go index b1884c2c04..2e44e9c9ec 100644 --- a/ssh/common.go +++ b/ssh/common.go @@ -6,6 +6,7 @@ package ssh import ( "crypto" + "crypto/fips140" "crypto/rand" "fmt" "io" @@ -256,6 +257,40 @@ type Algorithms struct { PublicKeyAuths []string } +func init() { + if fips140.Enabled() { + defaultHostKeyAlgos = slices.DeleteFunc(defaultHostKeyAlgos, func(algo string) bool { + _, err := hashFunc(underlyingAlgo(algo)) + return err != nil + }) + defaultPubKeyAuthAlgos = slices.DeleteFunc(defaultPubKeyAuthAlgos, func(algo string) bool { + _, err := hashFunc(underlyingAlgo(algo)) + return err != nil + }) + } +} + +func hashFunc(format string) (crypto.Hash, error) { + switch format { + case KeyAlgoRSASHA256, KeyAlgoECDSA256, KeyAlgoSKED25519, KeyAlgoSKECDSA256: + return crypto.SHA256, nil + case KeyAlgoECDSA384: + return crypto.SHA384, nil + case KeyAlgoRSASHA512, KeyAlgoECDSA521: + return crypto.SHA512, nil + case KeyAlgoED25519: + // KeyAlgoED25519 doesn't pre-hash. + return 0, nil + case KeyAlgoRSA, InsecureKeyAlgoDSA: + if fips140.Enabled() { + return 0, fmt.Errorf("ssh: hash algorithm for format %q not allowed in FIPS 140 mode", format) + } + return crypto.SHA1, nil + default: + return 0, fmt.Errorf("ssh: hash algorithm for format %q not mapped", format) + } +} + // SupportedAlgorithms returns algorithms currently implemented by this package, // excluding those with security issues, which are returned by // InsecureAlgorithms. The algorithms listed here are in preference order. @@ -283,21 +318,6 @@ func InsecureAlgorithms() Algorithms { var supportedCompressions = []string{compressionNone} -// hashFuncs keeps the mapping of supported signature algorithms to their -// respective hashes needed for signing and verification. -var hashFuncs = map[string]crypto.Hash{ - KeyAlgoRSA: crypto.SHA1, - KeyAlgoRSASHA256: crypto.SHA256, - KeyAlgoRSASHA512: crypto.SHA512, - InsecureKeyAlgoDSA: crypto.SHA1, - KeyAlgoECDSA256: crypto.SHA256, - KeyAlgoECDSA384: crypto.SHA384, - KeyAlgoECDSA521: crypto.SHA512, - // KeyAlgoED25519 doesn't pre-hash. - KeyAlgoSKECDSA256: crypto.SHA256, - KeyAlgoSKED25519: crypto.SHA256, -} - // algorithmsForKeyFormat returns the supported signature algorithms for a given // public key format (PublicKey.Type), in order of preference. See RFC 8332, // Section 2. See also the note in sendKexInit on backwards compatibility. diff --git a/ssh/doc.go b/ssh/doc.go index 04ccce3461..5b4de9effc 100644 --- a/ssh/doc.go +++ b/ssh/doc.go @@ -17,8 +17,18 @@ References: [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 [SSH-CERTS]: https://datatracker.ietf.org/doc/html/draft-miller-ssh-cert-01 + [FIPS 140-3 mode]: https://go.dev/doc/security/fips140 This package does not fall under the stability promise of the Go language itself, so its API may be changed when pressing needs arise. + +# FIPS 140-3 mode + +When the program is in [FIPS 140-3 mode], this package behaves as if only SP +800-140C and SP 800-140D approved cipher suites, signature algorithms, +certificate public key types and sizes, and key exchange and derivation +algorithms were implemented. Others are silently ignored and not negotiated, or +rejected. This set may depend on the algorithms supported by the FIPS 140-3 Go +Cryptographic Module selected with GOFIPS140, and may change across Go versions. */ package ssh diff --git a/ssh/kex.go b/ssh/kex.go index 78aaf03103..5f7fdd8514 100644 --- a/ssh/kex.go +++ b/ssh/kex.go @@ -8,12 +8,14 @@ import ( "crypto" "crypto/ecdsa" "crypto/elliptic" + "crypto/fips140" "crypto/rand" "encoding/binary" "errors" "fmt" "io" "math/big" + "slices" "golang.org/x/crypto/curve25519" ) @@ -395,9 +397,27 @@ func ecHash(curve elliptic.Curve) crypto.Hash { return crypto.SHA512 } +// kexAlgoMap defines the supported KEXs. KEXs not included are not supported +// and will not be negotiated, even if explicitly configured. When FIPS mode is +// enabled, only FIPS-approved algorithms are included. var kexAlgoMap = map[string]kexAlgorithm{} func init() { + // mlkem768x25519-sha256 we'll work with fips140=on but not fips140=only + // until Go 1.26. + kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{} + kexAlgoMap[KeyExchangeECDHP521] = &ecdh{elliptic.P521()} + kexAlgoMap[KeyExchangeECDHP384] = &ecdh{elliptic.P384()} + kexAlgoMap[KeyExchangeECDHP256] = &ecdh{elliptic.P256()} + + if fips140.Enabled() { + defaultKexAlgos = slices.DeleteFunc(defaultKexAlgos, func(algo string) bool { + _, ok := kexAlgoMap[algo] + return !ok + }) + return + } + p, _ := new(big.Int).SetString(oakleyGroup2, 16) kexAlgoMap[InsecureKeyExchangeDH1SHA1] = &dhGroup{ g: new(big.Int).SetInt64(2), @@ -431,14 +451,10 @@ func init() { hashFunc: crypto.SHA512, } - kexAlgoMap[KeyExchangeECDHP521] = &ecdh{elliptic.P521()} - kexAlgoMap[KeyExchangeECDHP384] = &ecdh{elliptic.P384()} - kexAlgoMap[KeyExchangeECDHP256] = &ecdh{elliptic.P256()} kexAlgoMap[KeyExchangeCurve25519] = &curve25519sha256{} kexAlgoMap[keyExchangeCurve25519LibSSH] = &curve25519sha256{} kexAlgoMap[InsecureKeyExchangeDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} kexAlgoMap[KeyExchangeDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} - kexAlgoMap[KeyExchangeMLKEM768X25519] = &mlkem768WithCurve25519sha256{} } // curve25519sha256 implements the curve25519-sha256 (formerly known as diff --git a/ssh/keys.go b/ssh/keys.go index c972169773..a035956fcc 100644 --- a/ssh/keys.go +++ b/ssh/keys.go @@ -504,7 +504,10 @@ func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { if !slices.Contains(supportedAlgos, sig.Format) { return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) } - hash := hashFuncs[sig.Format] + hash, err := hashFunc(sig.Format) + if err != nil { + return err + } h := hash.New() h.Write(data) digest := h.Sum(nil) @@ -621,7 +624,11 @@ func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error { if sig.Format != k.Type() { return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) } - h := hashFuncs[sig.Format].New() + hash, err := hashFunc(sig.Format) + if err != nil { + return err + } + h := hash.New() h.Write(data) digest := h.Sum(nil) @@ -666,7 +673,11 @@ func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) } - h := hashFuncs[k.PublicKey().Type()].New() + hash, err := hashFunc(k.PublicKey().Type()) + if err != nil { + return nil, err + } + h := hash.New() h.Write(data) digest := h.Sum(nil) r, s, err := dsa.Sign(rand, k.PrivateKey, digest) @@ -816,8 +827,11 @@ func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { if sig.Format != k.Type() { return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) } - - h := hashFuncs[sig.Format].New() + hash, err := hashFunc(sig.Format) + if err != nil { + return err + } + h := hash.New() h.Write(data) digest := h.Sum(nil) @@ -920,8 +934,11 @@ func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error { if sig.Format != k.Type() { return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) } - - h := hashFuncs[sig.Format].New() + hash, err := hashFunc(sig.Format) + if err != nil { + return err + } + h := hash.New() h.Write([]byte(k.application)) appDigest := h.Sum(nil) @@ -1024,7 +1041,11 @@ func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error { return fmt.Errorf("invalid size %d for Ed25519 public key", l) } - h := hashFuncs[sig.Format].New() + hash, err := hashFunc(sig.Format) + if err != nil { + return err + } + h := hash.New() h.Write([]byte(k.application)) appDigest := h.Sum(nil) @@ -1131,7 +1152,10 @@ func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type()) } - hashFunc := hashFuncs[algorithm] + hashFunc, err := hashFunc(algorithm) + if err != nil { + return nil, err + } var digest []byte if hashFunc != 0 { h := hashFunc.New() diff --git a/ssh/mac.go b/ssh/mac.go index de2639d57f..87d626fbbf 100644 --- a/ssh/mac.go +++ b/ssh/mac.go @@ -7,11 +7,13 @@ package ssh // Message authentication support import ( + "crypto/fips140" "crypto/hmac" "crypto/sha1" "crypto/sha256" "crypto/sha512" "hash" + "slices" ) type macMode struct { @@ -46,23 +48,37 @@ func (t truncatingMAC) Size() int { func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } -var macModes = map[string]*macMode{ - HMACSHA512ETM: {64, true, func(key []byte) hash.Hash { +// macModes defines the supported MACs. MACs not included are not supported +// and will not be negotiated, even if explicitly configured. When FIPS mode is +// enabled, only FIPS-approved algorithms are included. +var macModes = map[string]*macMode{} + +func init() { + macModes[HMACSHA512ETM] = &macMode{64, true, func(key []byte) hash.Hash { return hmac.New(sha512.New, key) - }}, - HMACSHA256ETM: {32, true, func(key []byte) hash.Hash { + }} + macModes[HMACSHA256ETM] = &macMode{32, true, func(key []byte) hash.Hash { return hmac.New(sha256.New, key) - }}, - HMACSHA512: {64, false, func(key []byte) hash.Hash { + }} + macModes[HMACSHA512] = &macMode{64, false, func(key []byte) hash.Hash { return hmac.New(sha512.New, key) - }}, - HMACSHA256: {32, false, func(key []byte) hash.Hash { + }} + macModes[HMACSHA256] = &macMode{32, false, func(key []byte) hash.Hash { return hmac.New(sha256.New, key) - }}, - HMACSHA1: {20, false, func(key []byte) hash.Hash { + }} + + if fips140.Enabled() { + defaultMACs = slices.DeleteFunc(defaultMACs, func(algo string) bool { + _, ok := macModes[algo] + return !ok + }) + return + } + + macModes[HMACSHA1] = &macMode{20, false, func(key []byte) hash.Hash { return hmac.New(sha1.New, key) - }}, - InsecureHMACSHA196: {20, false, func(key []byte) hash.Hash { + }} + macModes[InsecureHMACSHA196] = &macMode{20, false, func(key []byte) hash.Hash { return truncatingMAC{12, hmac.New(sha1.New, key)} - }}, + }} } diff --git a/ssh/transport.go b/ssh/transport.go index 663619845c..fa3dd6a429 100644 --- a/ssh/transport.go +++ b/ssh/transport.go @@ -8,6 +8,7 @@ import ( "bufio" "bytes" "errors" + "fmt" "io" "log" ) @@ -254,6 +255,9 @@ var ( // (to setup server->client keys) or clientKeys (for client->server keys). func newPacketCipher(d direction, algs DirectionAlgorithms, kex *kexResult) (packetCipher, error) { cipherMode := cipherModes[algs.Cipher] + if cipherMode == nil { + return nil, fmt.Errorf("ssh: unsupported cipher %v", algs.Cipher) + } iv := make([]byte, cipherMode.ivSize) key := make([]byte, cipherMode.keySize) From 2beaa59a3c994e5d01b6d58dc348dcd6d814ef26 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 15 Dec 2024 20:02:38 +0100 Subject: [PATCH 20/37] ssh: add VerifiedPublicKeyCallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes golang/go#70795 Change-Id: I9b7c91f35f89495d1e9b5f6ec0c036c02a61d774 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/636335 Reviewed-by: Michael Knyszek Reviewed-by: Junyang Shao Reviewed-by: Ilia Mirkin Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Jorge Hernández --- ssh/server.go | 27 ++++ ssh/server_test.go | 374 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 401 insertions(+) diff --git a/ssh/server.go b/ssh/server.go index f06c08cd46..064dcbaf5a 100644 --- a/ssh/server.go +++ b/ssh/server.go @@ -44,6 +44,9 @@ type Permissions struct { // pass data from the authentication callbacks to the server // application layer. Extensions map[string]string + + // ExtraData allows to store user defined data. + ExtraData map[any]any } type GSSAPIWithMICConfig struct { @@ -127,6 +130,21 @@ type ServerConfig struct { // Permissions.Extensions entry. PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) + // VerifiedPublicKeyCallback, if non-nil, is called after a client + // successfully confirms having control over a key that was previously + // approved by PublicKeyCallback. The permissions object passed to the + // callback is the one returned by PublicKeyCallback for the given public + // key and its ownership is transferred to the callback. The returned + // Permissions object can be the same object, optionally modified, or a + // completely new object. If VerifiedPublicKeyCallback is non-nil, + // PublicKeyCallback is not allowed to return a PartialSuccessError, which + // can instead be returned by VerifiedPublicKeyCallback. + // + // VerifiedPublicKeyCallback does not affect which authentication methods + // are included in the list of methods that can be attempted by the client. + VerifiedPublicKeyCallback func(conn ConnMetadata, key PublicKey, permissions *Permissions, + signatureAlgorithm string) (*Permissions, error) + // KeyboardInteractiveCallback, if non-nil, is called when // keyboard-interactive authentication is selected (RFC // 4256). The client object's Challenge function should be @@ -653,6 +671,9 @@ userAuthLoop: candidate.pubKeyData = pubKeyData candidate.perms, candidate.result = authConfig.PublicKeyCallback(s, pubKey) _, isPartialSuccessError := candidate.result.(*PartialSuccessError) + if isPartialSuccessError && config.VerifiedPublicKeyCallback != nil { + return nil, errors.New("ssh: invalid library usage: PublicKeyCallback must not return partial success when VerifiedPublicKeyCallback is defined") + } if (candidate.result == nil || isPartialSuccessError) && candidate.perms != nil && @@ -723,6 +744,12 @@ userAuthLoop: authErr = candidate.result perms = candidate.perms + if authErr == nil && config.VerifiedPublicKeyCallback != nil { + // Only call VerifiedPublicKeyCallback after the key has been accepted + // and successfully verified. If authErr is non-nil, the key is not + // considered verified and the callback must not run. + perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo) + } } case "gssapi-with-mic": if authConfig.GSSAPIWithMICConfig == nil { diff --git a/ssh/server_test.go b/ssh/server_test.go index 5bd18db5bb..e48f7e3059 100644 --- a/ssh/server_test.go +++ b/ssh/server_test.go @@ -434,6 +434,380 @@ func TestPreAuthConnAndBanners(t *testing.T) { } } +func TestVerifiedPublicKeyCallback(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + extraKey := "extra" + extraDataString := "just a string" + + serverConf := &ServerConfig{ + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + if permissions != nil && permissions.ExtraData != nil { + if !reflect.DeepEqual(map[any]any{extraKey: extraDataString}, permissions.ExtraData) { + t.Errorf("expected extra data: %v; got: %v", extraDataString, permissions.ExtraData) + } + } else { + t.Error("expected extra data is missing") + } + if signatureAlgorithm != KeyAlgoRSASHA256 { + t.Errorf("expected signature algorithm: %q; got: %q", KeyAlgoRSASHA256, signatureAlgorithm) + } + return permissions, nil + }, + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + return &Permissions{ExtraData: map[any]any{extraKey: extraDataString}}, nil + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + done := make(chan struct{}) + go func() { + defer close(done) + conn, _, _, err := NewServerConn(c1, serverConf) + if err != nil { + t.Errorf("unexpected server error: %v", err) + } + if !reflect.DeepEqual(map[any]any{extraKey: extraDataString}, conn.Permissions.ExtraData) { + t.Errorf("expected extra data: %v; got: %v", extraDataString, conn.Permissions.ExtraData) + } + }() + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err != nil { + t.Fatal(err) + } + <-done +} + +func TestVerifiedPublicCallbackPartialSuccess(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverConf := &ServerConfig{ + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { + return nil, nil + } + return nil, errors.New("invalid credentials") + }, + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { + return nil, &PartialSuccessError{ + Next: ServerAuthCallbacks{ + PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { + if string(password) == clientPassword { + return nil, nil + } + return nil, nil + }, + }, + } + } + return nil, errors.New("invalid credentials") + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + Password(clientPassword), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + go NewServerConn(c1, serverConf) + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err != nil { + t.Fatalf("client login error: %s", err) + } +} + +func TestVerifiedPublicKeyCallbackPwdAndKey(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverConf := &ServerConfig{ + PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { + if string(password) == clientPassword { + return nil, &PartialSuccessError{ + Next: ServerAuthCallbacks{ + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { + return nil, nil + } + return nil, errors.New("invalid credentials") + }, + }, + } + } + return nil, errors.New("invalid credentials") + + }, + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { + return nil, nil + } + return nil, errors.New("invalid credentials") + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + Password(clientPassword), + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + go NewServerConn(c1, serverConf) + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err != nil { + t.Fatalf("client login error: %s", err) + } +} + +func TestVerifiedPubKeyCallbackAuthMethods(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverConf := &ServerConfig{ + PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { + return nil, nil + }, + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { + return nil, nil + } + return nil, errors.New("invalid credentials") + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + go NewServerConn(c1, serverConf) + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err == nil { + t.Fatal("client login succeed with only VerifiedPublicKeyCallback defined") + } +} + +func TestVerifiedPubKeyCallbackError(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverConf := &ServerConfig{ + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + return nil, nil + }, + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + return nil, errors.New("invalid credentials") + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + go NewServerConn(c1, serverConf) + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err == nil { + t.Fatal("client login succeed with VerifiedPublicKeyCallback returning an error") + } +} + +func TestVerifiedPublicCallbackPartialSuccessBadUsage(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverConf := &ServerConfig{ + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { + // Returning PartialSuccessError is not permitted when + // VerifiedPublicKeyCallback is defined. This callback is + // invoked for both query requests and real authentications, + // while VerifiedPublicKeyCallback is only triggered if the + // client has proven control of the key. + return nil, &PartialSuccessError{ + Next: ServerAuthCallbacks{ + PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { + if string(password) == clientPassword { + return nil, nil + } + return nil, nil + }, + }, + } + } + return nil, errors.New("invalid credentials") + }, + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { + return nil, &PartialSuccessError{ + Next: ServerAuthCallbacks{ + PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { + if string(password) == clientPassword { + return nil, nil + } + return nil, nil + }, + }, + } + } + return nil, errors.New("invalid credentials") + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + Password(clientPassword), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + go NewServerConn(c1, serverConf) + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err == nil { + t.Fatal("authentication suceeded with PartialSuccess returned from PublicKeyCallback and VerifiedPublicKeyCallback defined") + } +} + +func TestVerifiedPublicKeyCallbackOnError(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + var verifiedCallbackCalled bool + + serverConf := &ServerConfig{ + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + verifiedCallbackCalled = true + return nil, nil + }, + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + return nil, errors.New("invalid key") + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + + done := make(chan struct{}) + go func() { + defer close(done) + NewServerConn(c1, serverConf) + }() + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err == nil { + t.Fatal("authentication should fail") + } + <-done + if verifiedCallbackCalled { + t.Error("VerifiedPublicKeyCallback called after PublicKeyCallback returned an error") + } +} + +func TestVerifiedPublicKeyCallbackOnly(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverConf := &ServerConfig{ + VerifiedPublicKeyCallback: func(conn ConnMetadata, key PublicKey, permissions *Permissions, signatureAlgorithm string) (*Permissions, error) { + return nil, nil + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + done := make(chan struct{}) + go func() { + defer close(done) + NewServerConn(c1, serverConf) + }() + + clientConf := ClientConfig{ + User: "user", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err == nil { + t.Fatal("authentication suceeded with only VerifiedPublicKeyCallback defined") + } + <-done +} + type markerConn struct { closed uint32 used uint32 From 1336e21bd6f39d1ab82ca6412693849c2d120e1d Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Mon, 6 Oct 2025 16:00:59 +0000 Subject: [PATCH 21/37] x509roots/fallback: update bundle This is an automated CL which updates the NSS root bundle. [git-generate] go generate ./x509roots Change-Id: I9ab454c977013b2f6a42bc93fb0649612c54c6c0 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/709475 Reviewed-by: Roland Shoemaker Auto-Submit: Gopher Robot LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- x509roots/fallback/bundle/bundle.der | Bin 154797 -> 156781 bytes x509roots/fallback/bundle/bundle.go | 132 +++++++++++++++------------ 2 files changed, 72 insertions(+), 60 deletions(-) diff --git a/x509roots/fallback/bundle/bundle.der b/x509roots/fallback/bundle/bundle.der index 1abf12f5980415e088cfe616e3c01c9fb5eb2108..7c75ce5e070fcfe21d67283484dcf8e72b024236 100644 GIT binary patch delta 1854 zcmb`GdpOgJAIA;JnEPd8bD3PWF@0wn5{DX+i9|X%LNRN`oR-d9szr$kEyGl9B|UCS zGPLX{ohLaF%5iI))J9Ak;TXC6ex1u7{c-;6&)4(%@2f~`md z(m{{Pl@vjWirU*&e;Fj!UqzA4=7VKtc_o0FiYn%!Pmi0jk`h41sRLjYrGv^UdWs|; zoDl&13)CRm0egdjz0AE6PBEg7CejiZI3!^9mr{bj{!u{`=1&x+`GJIlL~}0^$$SqE zFokM3-~l2&8iykg92}fOp&A5dfapN@8=XSG=^D3T7c3IG{j;v94z{SaNzE~J}W9J8% zagx2jZ36W>;@qP!hKAUvQsQ2WdFVkNn+)KdcyEDs+LuM?U3a@YQ1NN+6Mu+y!frt^ zVDjY{CYs8I%KHDMdA->nIJf&cm|cwlO!}UdaRLK9zAFeuzBG)H2gRux?&#A!&5nY< zl{hQx7{Laad#NKLsW_6=tRhY!@6x^Luw&AZYpj}@#|B@WG*Vu_f(%NI$JBUAMIazOX`AD6+-mDpQvwnYT>%j2_2C&2aqAE^#0)KeoWN z2Nud8cdT!{YHuv`l}8iMqjz)mzstEop74P)?9XYtOUvLCcO8N35Uot0Fq2_<-SSUl z39n|2z*eLiaQLmIp+@XG*~6dXQR~jn*%Ci~Y|n^4H!rsvLVc`GF6@b+1|9E$>f|1l z*A>HsxyLs3Dq90wkP&v z!>lQ9MWFER@R!7u#UuB8#B(E8C!)7Px2q0#ZB zX3kg7`Cpo+a}9*xnnbCx3Do2VE*%qY@@-5Z_>Vlkjaj+B+JiseKq0p?UZ2ei+%TXF zh0&u8=PrA_fRG$Li6iXIWEaF#ht!SE`VFZqSza{vuWq}vh$yapD*{}guN+8yHJ6!) zK$PE@W2Y2LJ##G+Q6gHeMHPl04SQ&Thxr)pm%Z3NUAcFZ?aIDmBy!~Ey%#Q#2WC|H zACfkqPmW}=rl_m{g_!!K1|^p^-P5~>6H9mDd#-dP%LgAr8UB>{l{bgl^V23$LNr>v z*$LM+&P+n3X*R7}vO>npE9FJlYeqC$t~I-luL*gedOxhWXXe4xFlU-Qek6D4jr zQ)l$!jz(YfzRMm8e%3t1G4!s?cv0#inbb3EHrUo(jXtoU(6P+P4Y_(rb*!*vvOl)^ zB5`@ZD`~f{_qtMN_;Ad!7sXQ0mYI6cyhL8ogjp9JGwO=lS>GS;99Nrq*EDB+x^$Cn zAQY$H=qh@9@)oDO{Mq;vsH#H0xU>C6oxy&5&g^N-m6PlO50dqI+8s>94o-_rS0HPp zkZanzz&c~*&Aoltw7~Nj_Ehx!!PRkBnoPL~q5j_6b029ZZ|@16pDml8@|nRZn{?PJ zON_QVP#VulJ+`5>FSp1608Z!*S`j5>D+$F-GqG^KOuN6(kg0;S>hKd?{jn7y4YxRt UeciU1q5OkD`g2Qe1juaT{|HeRK>z>% delta 17 ZcmaERf^+Ro&W0_F6XLfAq%+F?1prKT2ipJu diff --git a/x509roots/fallback/bundle/bundle.go b/x509roots/fallback/bundle/bundle.go index be9e857790..8b8f20a470 100644 --- a/x509roots/fallback/bundle/bundle.go +++ b/x509roots/fallback/bundle/bundle.go @@ -521,365 +521,377 @@ var unparsedCertificates = []unparsedCertificate{ certStartOff: 88949, certLength: 1049, }, + { + cn: "CN=OISTE Server Root ECC G1,O=OISTE Foundation,C=CH", + sha256Hash: "eec997c0c30f216f7e3b8b307d2bae42412d753fc8219dafd1520b2572850f49", + certStartOff: 89998, + certLength: 569, + }, + { + cn: "CN=OISTE Server Root RSA G1,O=OISTE Foundation,C=CH", + sha256Hash: "9ae36232a5189ffddb353dfd26520c015395d22777dac59db57b98c089a651e6", + certStartOff: 90567, + certLength: 1415, + }, { cn: "CN=OISTE WISeKey Global Root GB CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH", sha256Hash: "6b9c08e86eb0f767cfad65cd98b62149e5494a67f5845e7bd1ed019f27b86bd6", - certStartOff: 89998, + certStartOff: 91982, certLength: 953, }, { cn: "CN=OISTE WISeKey Global Root GC CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH", sha256Hash: "8560f91c3624daba9570b5fea0dbe36ff11a8323be9486854fb3f34a5571198d", - certStartOff: 90951, + certStartOff: 92935, certLength: 621, }, { cn: "CN=QuoVadis Root CA 1 G3,O=QuoVadis Limited,C=BM", sha256Hash: "8a866fd1b276b57e578e921c65828a2bed58e9f2f288054134b7f1f4bfc9cc74", - certStartOff: 91572, + certStartOff: 93556, certLength: 1380, }, { cn: "CN=QuoVadis Root CA 2 G3,O=QuoVadis Limited,C=BM", sha256Hash: "8fe4fb0af93a4d0d67db0bebb23e37c71bf325dcbcdd240ea04daf58b47e1840", - certStartOff: 92952, + certStartOff: 94936, certLength: 1380, }, { cn: "CN=QuoVadis Root CA 2,O=QuoVadis Limited,C=BM", sha256Hash: "85a0dd7dd720adb7ff05f83d542b209dc7ff4528f7d677b18389fea5e5c49e86", - certStartOff: 94332, + certStartOff: 96316, certLength: 1467, }, { cn: "CN=QuoVadis Root CA 3 G3,O=QuoVadis Limited,C=BM", sha256Hash: "88ef81de202eb018452e43f864725cea5fbd1fc2d9d205730709c5d8b8690f46", - certStartOff: 95799, + certStartOff: 97783, certLength: 1380, }, { cn: "CN=QuoVadis Root CA 3,O=QuoVadis Limited,C=BM", sha256Hash: "18f1fc7f205df8adddeb7fe007dd57e3af375a9c4d8d73546bf4f1fed1e18d35", - certStartOff: 97179, + certStartOff: 99163, certLength: 1697, }, { cn: "CN=SSL.com EV Root Certification Authority ECC,O=SSL Corporation,L=Houston,ST=Texas,C=US", sha256Hash: "22a2c1f7bded704cc1e701b5f408c310880fe956b5de2a4a44f99c873a25a7c8", - certStartOff: 98876, + certStartOff: 100860, certLength: 664, }, { cn: "CN=SSL.com EV Root Certification Authority RSA R2,O=SSL Corporation,L=Houston,ST=Texas,C=US", sha256Hash: "2e7bf16cc22485a7bbe2aa8696750761b0ae39be3b2fe9d0cc6d4ef73491425c", - certStartOff: 99540, + certStartOff: 101524, certLength: 1519, }, { cn: "CN=SSL.com Root Certification Authority ECC,O=SSL Corporation,L=Houston,ST=Texas,C=US", sha256Hash: "3417bb06cc6007da1b961c920b8ab4ce3fad820e4aa30b9acbc4a74ebdcebc65", - certStartOff: 101059, + certStartOff: 103043, certLength: 657, }, { cn: "CN=SSL.com Root Certification Authority RSA,O=SSL Corporation,L=Houston,ST=Texas,C=US", sha256Hash: "85666a562ee0be5ce925c1d8890a6f76a87ec16d4d7d5f29ea7419cf20123b69", - certStartOff: 101716, + certStartOff: 103700, certLength: 1505, }, { cn: "CN=SSL.com TLS ECC Root CA 2022,O=SSL Corporation,C=US", sha256Hash: "c32ffd9f46f936d16c3673990959434b9ad60aafbb9e7cf33654f144cc1ba143", - certStartOff: 103221, + certStartOff: 105205, certLength: 574, }, { cn: "CN=SSL.com TLS RSA Root CA 2022,O=SSL Corporation,C=US", sha256Hash: "8faf7d2e2cb4709bb8e0b33666bf75a5dd45b5de480f8ea8d4bfe6bebc17f2ed", - certStartOff: 103795, + certStartOff: 105779, certLength: 1421, }, { cn: "CN=SZAFIR ROOT CA2,O=Krajowa Izba Rozliczeniowa S.A.,C=PL", sha256Hash: "a1339d33281a0b56e557d3d32b1ce7f9367eb094bd5fa72a7e5004c8ded7cafe", - certStartOff: 105216, + certStartOff: 107200, certLength: 886, }, { cn: "CN=Sectigo Public Server Authentication Root E46,O=Sectigo Limited,C=GB", sha256Hash: "c90f26f0fb1b4018b22227519b5ca2b53e2ca5b3be5cf18efe1bef47380c5383", - certStartOff: 106102, + certStartOff: 108086, certLength: 574, }, { cn: "CN=Sectigo Public Server Authentication Root R46,O=Sectigo Limited,C=GB", sha256Hash: "7bb647a62aeeac88bf257aa522d01ffea395e0ab45c73f93f65654ec38f25a06", - certStartOff: 106676, + certStartOff: 108660, certLength: 1422, }, { cn: "CN=Secure Global CA,O=SecureTrust Corporation,C=US", sha256Hash: "4200f5043ac8590ebb527d209ed1503029fbcbd41ca1b506ec27f15ade7dac69", - certStartOff: 108098, + certStartOff: 110082, certLength: 960, }, { cn: "CN=SecureSign Root CA12,O=Cybertrust Japan Co.\\, Ltd.,C=JP", sha256Hash: "3f034bb5704d44b2d08545a02057de93ebf3905fce721acbc730c06ddaee904e", - certStartOff: 109058, + certStartOff: 111042, certLength: 886, }, { cn: "CN=SecureSign Root CA14,O=Cybertrust Japan Co.\\, Ltd.,C=JP", sha256Hash: "4b009c1034494f9ab56bba3ba1d62731fc4d20d8955adcec10a925607261e338", - certStartOff: 109944, + certStartOff: 111928, certLength: 1398, }, { cn: "CN=SecureSign Root CA15,O=Cybertrust Japan Co.\\, Ltd.,C=JP", sha256Hash: "e778f0f095fe843729cd1a0082179e5314a9c291442805e1fb1d8fb6b8886c3a", - certStartOff: 111342, + certStartOff: 113326, certLength: 551, }, { cn: "CN=SecureTrust CA,O=SecureTrust Corporation,C=US", sha256Hash: "f1c1b50ae5a20dd8030ec9f6bc24823dd367b5255759b4e71b61fce9f7375d73", - certStartOff: 111893, + certStartOff: 113877, certLength: 956, }, { cn: "CN=Security Communication ECC RootCA1,O=SECOM Trust Systems CO.\\,LTD.,C=JP", sha256Hash: "e74fbda55bd564c473a36b441aa799c8a68e077440e8288b9fa1e50e4bbaca11", - certStartOff: 112849, + certStartOff: 114833, certLength: 572, }, { cn: "CN=Starfield Root Certificate Authority - G2,O=Starfield Technologies\\, Inc.,L=Scottsdale,ST=Arizona,C=US", sha256Hash: "2ce1cb0bf9d2f9e102993fbe215152c3b2dd0cabde1c68e5319b839154dbb7f5", - certStartOff: 113421, + certStartOff: 115405, certLength: 993, }, { cn: "CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies\\, Inc.,L=Scottsdale,ST=Arizona,C=US", sha256Hash: "568d6905a2c88708a4b3025190edcfedb1974a606a13c6e5290fcb2ae63edab5", - certStartOff: 114414, + certStartOff: 116398, certLength: 1011, }, { cn: "CN=SwissSign Gold CA - G2,O=SwissSign AG,C=CH", sha256Hash: "62dd0be9b9f50a163ea0f8e75c053b1eca57ea55c8688f647c6881f2c8357b95", - certStartOff: 115425, + certStartOff: 117409, certLength: 1470, }, { cn: "CN=SwissSign RSA TLS Root CA 2022 - 1,O=SwissSign AG,C=CH", sha256Hash: "193144f431e0fddb740717d4de926a571133884b4360d30e272913cbe660ce41", - certStartOff: 116895, + certStartOff: 118879, certLength: 1431, }, { cn: "CN=T-TeleSec GlobalRoot Class 2,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE", sha256Hash: "91e2f5788d5810eba7ba58737de1548a8ecacd014598bc0b143e041b17052552", - certStartOff: 118326, + certStartOff: 120310, certLength: 967, }, { cn: "CN=T-TeleSec GlobalRoot Class 3,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE", sha256Hash: "fd73dad31c644ff1b43bef0ccdda96710b9cd9875eca7e31707af3e96d522bbd", - certStartOff: 119293, + certStartOff: 121277, certLength: 967, }, { cn: "CN=TWCA CYBER Root CA,OU=Root CA,O=TAIWAN-CA,C=TW", sha256Hash: "3f63bb2814be174ec8b6439cf08d6d56f0b7c405883a5648a334424d6b3ec558", - certStartOff: 120260, + certStartOff: 122244, certLength: 1425, }, { cn: "CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW", sha256Hash: "59769007f7685d0fcd50872f9f95d5755a5b2b457d81f3692b610a98672f0e1b", - certStartOff: 121685, + certStartOff: 123669, certLength: 1349, }, { cn: "CN=TWCA Root Certification Authority,OU=Root CA,O=TAIWAN-CA,C=TW", sha256Hash: "bfd88fe1101c41ae3e801bf8be56350ee9bad1a6b9bd515edc5c6d5b8711ac44", - certStartOff: 123034, + certStartOff: 125018, certLength: 895, }, { cn: "CN=Telekom Security TLS ECC Root 2020,O=Deutsche Telekom Security GmbH,C=DE", sha256Hash: "578af4ded0853f4e5998db4aeaf9cbea8d945f60b620a38d1a3c13b2bc7ba8e1", - certStartOff: 123929, + certStartOff: 125913, certLength: 582, }, { cn: "CN=Telekom Security TLS RSA Root 2023,O=Deutsche Telekom Security GmbH,C=DE", sha256Hash: "efc65cadbb59adb6efe84da22311b35624b71b3b1ea0da8b6655174ec8978646", - certStartOff: 124511, + certStartOff: 126495, certLength: 1463, }, { cn: "CN=Telia Root CA v2,O=Telia Finland Oyj,C=FI", sha256Hash: "242b69742fcb1e5b2abf98898b94572187544e5b4d9911786573621f6a74b82c", - certStartOff: 125974, + certStartOff: 127958, certLength: 1400, }, { cn: "CN=TeliaSonera Root CA v1,O=TeliaSonera", sha256Hash: "dd6936fe21f8f077c123a1a521c12224f72255b73e03a7260693e8a24b0fa389", - certStartOff: 127374, + certStartOff: 129358, certLength: 1340, }, { cn: "CN=TrustAsia Global Root CA G3,O=TrustAsia Technologies\\, Inc.,C=CN", sha256Hash: "e0d3226aeb1163c2e48ff9be3b50b4c6431be7bb1eacc5c36b5d5ec509039a08", - certStartOff: 128714, + certStartOff: 130698, certLength: 1449, }, { cn: "CN=TrustAsia Global Root CA G4,O=TrustAsia Technologies\\, Inc.,C=CN", sha256Hash: "be4b56cb5056c0136a526df444508daa36a0b54f42e4ac38f72af470e479654c", - certStartOff: 130163, + certStartOff: 132147, certLength: 601, }, { cn: "CN=TrustAsia TLS ECC Root CA,O=TrustAsia Technologies\\, Inc.,C=CN", sha256Hash: "c0076b9ef0531fb1a656d67c4ebe97cd5dbaa41ef44598acc2489878c92d8711", - certStartOff: 130764, + certStartOff: 132748, certLength: 565, }, { cn: "CN=TrustAsia TLS RSA Root CA,O=TrustAsia Technologies\\, Inc.,C=CN", sha256Hash: "06c08d7dafd876971eb1124fe67f847ec0c7a158d3ea53cbe940e2ea9791f4c3", - certStartOff: 131329, + certStartOff: 133313, certLength: 1412, }, { cn: "CN=Trustwave Global Certification Authority,O=Trustwave Holdings\\, Inc.,L=Chicago,ST=Illinois,C=US", sha256Hash: "97552015f5ddfc3c8788c006944555408894450084f100867086bc1a2bb58dc8", - certStartOff: 132741, + certStartOff: 134725, certLength: 1502, }, { cn: "CN=Trustwave Global ECC P256 Certification Authority,O=Trustwave Holdings\\, Inc.,L=Chicago,ST=Illinois,C=US", sha256Hash: "945bbc825ea554f489d1fd51a73ddf2ea624ac7019a05205225c22a78ccfa8b4", - certStartOff: 134243, + certStartOff: 136227, certLength: 612, }, { cn: "CN=Trustwave Global ECC P384 Certification Authority,O=Trustwave Holdings\\, Inc.,L=Chicago,ST=Illinois,C=US", sha256Hash: "55903859c8c0c3ebb8759ece4e2557225ff5758bbd38ebd48276601e1bd58097", - certStartOff: 134855, + certStartOff: 136839, certLength: 673, }, { cn: "CN=TunTrust Root CA,O=Agence Nationale de Certification Electronique,C=TN", sha256Hash: "2e44102ab58cb85419451c8e19d9acf3662cafbc614b6a53960a30f7d0e2eb41", - certStartOff: 135528, + certStartOff: 137512, certLength: 1463, }, { cn: "CN=UCA Extended Validation Root,O=UniTrust,C=CN", sha256Hash: "d43af9b35473755c9684fc06d7d8cb70ee5c28e773fb294eb41ee71722924d24", - certStartOff: 136991, + certStartOff: 138975, certLength: 1374, }, { cn: "CN=UCA Global G2 Root,O=UniTrust,C=CN", sha256Hash: "9bea11c976fe014764c1be56a6f914b5a560317abd9988393382e5161aa0493c", - certStartOff: 138365, + certStartOff: 140349, certLength: 1354, }, { cn: "CN=USERTrust ECC Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US", sha256Hash: "4ff460d54b9c86dabfbcfc5712e0400d2bed3fbc4d4fbdaa86e06adcd2a9ad7a", - certStartOff: 139719, + certStartOff: 141703, certLength: 659, }, { cn: "CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US", sha256Hash: "e793c9b02fd8aa13e21c31228accb08119643b749c898964b1746d46c3d4cbd2", - certStartOff: 140378, + certStartOff: 142362, certLength: 1506, }, { cn: "CN=e-Szigno Root CA 2017,O=Microsec Ltd.,L=Budapest,C=HU,2.5.4.97=#130e56415448552d3233353834343937", sha256Hash: "beb00b30839b9bc32c32e4447905950641f26421b15ed089198b518ae2ea1b99", - certStartOff: 141884, + certStartOff: 143868, certLength: 580, }, { cn: "CN=emSign ECC Root CA - C3,OU=emSign PKI,O=eMudhra Inc,C=US", sha256Hash: "bc4d809b15189d78db3e1d8cf4f9726a795da1643ca5f1358e1ddb0edc0d7eb3", - certStartOff: 142464, + certStartOff: 144448, certLength: 559, }, { cn: "CN=emSign ECC Root CA - G3,OU=emSign PKI,O=eMudhra Technologies Limited,C=IN", sha256Hash: "86a1ecba089c4a8d3bbe2734c612ba341d813e043cf9e8a862cd5c57a36bbe6b", - certStartOff: 143023, + certStartOff: 145007, certLength: 594, }, { cn: "CN=emSign Root CA - C1,OU=emSign PKI,O=eMudhra Inc,C=US", sha256Hash: "125609aa301da0a249b97a8239cb6a34216f44dcac9f3954b14292f2e8c8608f", - certStartOff: 143617, + certStartOff: 145601, certLength: 887, }, { cn: "CN=emSign Root CA - G1,OU=emSign PKI,O=eMudhra Technologies Limited,C=IN", sha256Hash: "40f6af0346a99aa1cd1d555a4e9cce62c7f9634603ee406615833dc8c8d00367", - certStartOff: 144504, + certStartOff: 146488, certLength: 920, }, { cn: "CN=vTrus ECC Root CA,O=iTrusChina Co.\\,Ltd.,C=CN", sha256Hash: "30fbba2c32238e2a98547af97931e550428b9b3f1c8eeb6633dcfa86c5b27dd3", - certStartOff: 145424, + certStartOff: 147408, certLength: 531, }, { cn: "CN=vTrus Root CA,O=iTrusChina Co.\\,Ltd.,C=CN", sha256Hash: "8a71de6559336f426c26e53880d00d88a18da4c6a91f0dcb6194e206c5c96387", - certStartOff: 145955, + certStartOff: 147939, certLength: 1370, }, { cn: "OU=AC RAIZ FNMT-RCM,O=FNMT-RCM,C=ES", sha256Hash: "ebc5570c29018c4d67b1aa127baf12f703b4611ebc17b7dab5573894179b93fa", - certStartOff: 147325, + certStartOff: 149309, certLength: 1415, }, { cn: "OU=Security Communication RootCA2,O=SECOM Trust Systems CO.\\,LTD.,C=JP", sha256Hash: "513b2cecb810d4cde5dd85391adfc6c2dd60d87bb736d2b521484aa47a0ebef6", - certStartOff: 148740, + certStartOff: 150724, certLength: 891, }, { cn: "OU=certSIGN ROOT CA G2,O=CERTSIGN SA,C=RO", sha256Hash: "657cfe2fa73faa38462571f332a2363a46fce7020951710702cdfbb6eeda3305", - certStartOff: 149631, + certStartOff: 151615, certLength: 1355, }, { cn: "OU=certSIGN ROOT CA,O=certSIGN,C=RO", sha256Hash: "eaa962c4fa4a6bafebe415196d351ccd888d4f53f3fa8ae6d7c466a94e6042bb", - certStartOff: 150986, + certStartOff: 152970, certLength: 828, }, { cn: "OU=ePKI Root Certification Authority,O=Chunghwa Telecom Co.\\, Ltd.,C=TW", sha256Hash: "c0a6f4dc63a24bfdcf54ef2a6a082a0a72de35803e2ff5ff527ae5d87206dfd5", - certStartOff: 151814, + certStartOff: 153798, certLength: 1460, distrustAfter: "2025-04-15T23:59:59Z", }, { cn: "SERIALNUMBER=G63287510,CN=ANF Secure Server Root CA,OU=ANF CA Raiz,O=ANF Autoridad de Certificacion,C=ES", sha256Hash: "fb8fec759169b9106b1e511644c618c51304373f6c0643088d8beffd1b997599", - certStartOff: 153274, + certStartOff: 155258, certLength: 1523, }, } From dca4914afe94ebd485672b06b9a120e18b452533 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 8 Oct 2025 10:15:41 -0400 Subject: [PATCH 22/37] acme: fix autocert TestHTTPHandlerDefaultFallback The Go 1.25.2 release made net/url stricter about parsing bracketed IPv6 hostnames, and is rejecting some test URLs used in the autocert TestHTTPHandlerDefaultFallback test with an error about the colon-separated fields requiring at least one hex digit. This commit replaces the invalid `xxxx` portion of some test URLS with valid hex digits, fixing the test regression. Change-Id: I84c192b1cd6daf53ef4199f7987437fd825f7041 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/710155 Reviewed-by: Roland Shoemaker Auto-Submit: Daniel McCarney Reviewed-by: Filippo Valsorda Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- acme/autocert/autocert_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acme/autocert/autocert_test.go b/acme/autocert/autocert_test.go index 269bc2a6c2..8ca8e2b3a7 100644 --- a/acme/autocert/autocert_test.go +++ b/acme/autocert/autocert_test.go @@ -561,9 +561,9 @@ func TestHTTPHandlerDefaultFallback(t *testing.T) { {"GET", "http://example.org/foo?a=b", 302, "https://example.org/foo?a=b"}, {"GET", "http://example.org:80/foo?a=b", 302, "https://example.org:443/foo?a=b"}, {"GET", "http://example.org:80/foo%20bar", 302, "https://example.org:443/foo%20bar"}, - {"GET", "http://[2602:d1:xxxx::c60a]:1234", 302, "https://[2602:d1:xxxx::c60a]:443/"}, - {"GET", "http://[2602:d1:xxxx::c60a]", 302, "https://[2602:d1:xxxx::c60a]/"}, - {"GET", "http://[2602:d1:xxxx::c60a]/foo?a=b", 302, "https://[2602:d1:xxxx::c60a]/foo?a=b"}, + {"GET", "http://[2602:d1:abcd::c60a]:1234", 302, "https://[2602:d1:abcd::c60a]:443/"}, + {"GET", "http://[2602:d1:abcd::c60a]", 302, "https://[2602:d1:abcd::c60a]/"}, + {"GET", "http://[2602:d1:abcd::c60a]/foo?a=b", 302, "https://[2602:d1:abcd::c60a]/foo?a=b"}, {"HEAD", "http://example.org", 302, "https://example.org/"}, {"HEAD", "http://example.org/foo", 302, "https://example.org/foo"}, {"HEAD", "http://example.org/foo/bar/", 302, "https://example.org/foo/bar/"}, From 627cb894b6b2021e34c4ad4af4c0a963127491e4 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Wed, 8 Oct 2025 08:52:20 -0700 Subject: [PATCH 23/37] go.mod: update golang.org/x dependencies Update golang.org/x dependencies to their latest tagged versions. Change-Id: Icf986acf9290649488777328f470200bf9e11442 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/710098 Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Auto-Submit: Dmitri Shuralyov --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index fd65b61893..f331951a16 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module golang.org/x/crypto go 1.24.0 require ( - golang.org/x/net v0.43.0 // tagx:ignore - golang.org/x/sys v0.36.0 - golang.org/x/term v0.35.0 + golang.org/x/net v0.45.0 // tagx:ignore + golang.org/x/sys v0.37.0 + golang.org/x/term v0.36.0 ) -require golang.org/x/text v0.29.0 // indirect +require golang.org/x/text v0.30.0 // indirect diff --git a/go.sum b/go.sum index c3f2d576cb..6d9f239e86 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= -golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= -golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= +golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= From 1faea2975ced2153e5086c1ee135f983db10150a Mon Sep 17 00:00:00 2001 From: cuishuang Date: Mon, 29 Sep 2025 11:51:24 +0800 Subject: [PATCH 24/37] all: fix some typos in comment Change-Id: Ia209f0a6d9b19d14e655c65d1287a1416b48c487 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/707535 Reviewed-by: Carlos Amedee Reviewed-by: Michael Pratt Auto-Submit: Sean Liao Reviewed-by: Nicola Murino LUCI-TryBot-Result: Go LUCI Reviewed-by: Sean Liao --- acme/autocert/internal/acmetest/ca.go | 2 +- acme/rfc8555.go | 2 +- chacha20/chacha_arm64.s | 2 +- internal/wycheproof/rsa_pss_test.go | 2 +- nacl/box/box_test.go | 2 +- nacl/sign/sign_test.go | 2 +- openpgp/packet/opaque_test.go | 2 +- openpgp/s2k/s2k.go | 2 +- ssh/agent/keyring.go | 2 +- ssh/agent/keyring_test.go | 2 +- ssh/client_auth_test.go | 2 +- ssh/example_test.go | 6 +++--- ssh/handshake_test.go | 2 +- ssh/server_test.go | 4 ++-- ssh/test/recording_client_test.go | 2 +- ssh/test/recording_server_test.go | 2 +- x509roots/nss/parser.go | 2 +- 17 files changed, 20 insertions(+), 20 deletions(-) diff --git a/acme/autocert/internal/acmetest/ca.go b/acme/autocert/internal/acmetest/ca.go index 28e6e7da66..c7ddd3dbfb 100644 --- a/acme/autocert/internal/acmetest/ca.go +++ b/acme/autocert/internal/acmetest/ca.go @@ -145,7 +145,7 @@ func (ca *CAServer) URL() string { return ca.url } -// Roots returns a pool cointaining the CA root. +// Roots returns a pool containing the CA root. func (ca *CAServer) Roots() *x509.CertPool { if ca.url == "" { panic("Roots called before Start") diff --git a/acme/rfc8555.go b/acme/rfc8555.go index fc653f3f0b..976b27702a 100644 --- a/acme/rfc8555.go +++ b/acme/rfc8555.go @@ -232,7 +232,7 @@ func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderO return responseOrder(res) } -// GetOrder retrives an order identified by the given URL. +// GetOrder retrieves an order identified by the given URL. // For orders created with AuthorizeOrder, the url value is Order.URI. // // If a caller needs to poll an order until its status is final, diff --git a/chacha20/chacha_arm64.s b/chacha20/chacha_arm64.s index 7dd2638e88..769af387e2 100644 --- a/chacha20/chacha_arm64.s +++ b/chacha20/chacha_arm64.s @@ -29,7 +29,7 @@ loop: MOVD $NUM_ROUNDS, R21 VLD1 (R11), [V30.S4, V31.S4] - // load contants + // load constants // VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4] WORD $0x4D60E940 diff --git a/internal/wycheproof/rsa_pss_test.go b/internal/wycheproof/rsa_pss_test.go index 2ad9a4313b..f2f9b6ebae 100644 --- a/internal/wycheproof/rsa_pss_test.go +++ b/internal/wycheproof/rsa_pss_test.go @@ -141,7 +141,7 @@ func TestRsaPss(t *testing.T) { } // Run all the tests twice: the first time with the salt length // as PSSSaltLengthAuto, and the second time with the salt length - // explictily set to tg.SLen. + // explicitly set to tg.SLen. for i := 0; i < 2; i++ { for _, sig := range tg.Tests { h.Reset() diff --git a/nacl/box/box_test.go b/nacl/box/box_test.go index cce1f3b4da..404925743c 100644 --- a/nacl/box/box_test.go +++ b/nacl/box/box_test.go @@ -114,7 +114,7 @@ func TestSealOpenAnonymous(t *testing.T) { t.Fatal("expected out to be unchanged") } if !bytes.HasPrefix(box, orig) { - t.Fatal("expected out to be coppied to returned slice") + t.Fatal("expected out to be copied to returned slice") } _, ok = OpenAnonymous(nil, box[len(out):], publicKey, privateKey) if !ok { diff --git a/nacl/sign/sign_test.go b/nacl/sign/sign_test.go index db269014c2..95ba801f2c 100644 --- a/nacl/sign/sign_test.go +++ b/nacl/sign/sign_test.go @@ -69,6 +69,6 @@ func TestGenerateSignOpen(t *testing.T) { } if !bytes.Equal(message, testMessage) { - t.Fatalf("verified message does not match signed messge, got\n%x\n, expected\n%x", message, testMessage) + t.Fatalf("verified message does not match signed message, got\n%x\n, expected\n%x", message, testMessage) } } diff --git a/openpgp/packet/opaque_test.go b/openpgp/packet/opaque_test.go index 61159f4683..06a3bbf019 100644 --- a/openpgp/packet/opaque_test.go +++ b/openpgp/packet/opaque_test.go @@ -51,7 +51,7 @@ func TestOpaqueParseReason(t *testing.T) { const expectedBad = 3 // Test post-conditions, make sure we actually parsed packets as expected. if badPackets != expectedBad { - t.Errorf("unexpected # unparseable packets: %d (want %d)", badPackets, expectedBad) + t.Errorf("unexpected # unparsable packets: %d (want %d)", badPackets, expectedBad) } if uid == nil { t.Errorf("failed to find expected UID in unsupported keyring") diff --git a/openpgp/s2k/s2k.go b/openpgp/s2k/s2k.go index fa1a919079..490cb633ce 100644 --- a/openpgp/s2k/s2k.go +++ b/openpgp/s2k/s2k.go @@ -53,7 +53,7 @@ func (c *Config) hash() crypto.Hash { func (c *Config) encodedCount() uint8 { if c == nil || c.S2KCount == 0 { - return 96 // The common case. Correspoding to 65536 + return 96 // The common case. Corresponding to 65536 } i := c.S2KCount diff --git a/ssh/agent/keyring.go b/ssh/agent/keyring.go index c1b4361087..d129875510 100644 --- a/ssh/agent/keyring.go +++ b/ssh/agent/keyring.go @@ -112,7 +112,7 @@ func (r *keyring) Unlock(passphrase []byte) error { } // expireKeysLocked removes expired keys from the keyring. If a key was added -// with a lifetimesecs contraint and seconds >= lifetimesecs seconds have +// with a lifetimesecs constraint and seconds >= lifetimesecs seconds have // elapsed, it is removed. The caller *must* be holding the keyring mutex. func (r *keyring) expireKeysLocked() { for _, k := range r.keys { diff --git a/ssh/agent/keyring_test.go b/ssh/agent/keyring_test.go index e9c90a3131..5e495d56d3 100644 --- a/ssh/agent/keyring_test.go +++ b/ssh/agent/keyring_test.go @@ -30,7 +30,7 @@ func validateListedKeys(t *testing.T, a Agent, expectedKeys []string) { return } if len(listedKeys) != len(expectedKeys) { - t.Fatalf("expeted %d key, got %d", len(expectedKeys), len(listedKeys)) + t.Fatalf("expected %d key, got %d", len(expectedKeys), len(listedKeys)) return } actualKeys := make(map[string]bool) diff --git a/ssh/client_auth_test.go b/ssh/client_auth_test.go index e398c4062c..a183c2183e 100644 --- a/ssh/client_auth_test.go +++ b/ssh/client_auth_test.go @@ -1136,7 +1136,7 @@ func TestPickSignatureAlgorithm(t *testing.T) { t.Fatalf("error generating cert signer: %v", err) } // The signer supports the public key algorithm and the - // public key format is a certificate type so the cerificate + // public key format is a certificate type so the certificate // algorithm matching the key format must be returned _, algo, err = pickSignatureAlgorithm(certSigner, c.extensions) if err != nil { diff --git a/ssh/example_test.go b/ssh/example_test.go index d6bad3e215..653f2c8f50 100644 --- a/ssh/example_test.go +++ b/ssh/example_test.go @@ -155,7 +155,7 @@ func ExampleNewServerConn() { } func ExampleServerConfig() { - // Minimal ServerConfig with SHA-1 algoritms disabled and supporting only + // Minimal ServerConfig with SHA-1 algorithms disabled and supporting only // public key authentication. // The algorithms returned by ssh.SupportedAlgorithms() are different from @@ -344,7 +344,7 @@ func ExampleClientConfig() { log.Fatalf("unable to parse private key: %v", err) } - // Minimal ClientConfig with SHA-1 algoritms disabled. + // Minimal ClientConfig with SHA-1 algorithms disabled. // The algorithms returned by ssh.SupportedAlgorithms() are different from // the default ones and do not include algorithms that are considered // insecure, such as those using SHA-1, returned by @@ -361,7 +361,7 @@ func ExampleClientConfig() { ssh.PublicKeys(signer), }, HostKeyCallback: ssh.FixedHostKey(hostKey), - // We should check that hostKey algorithm is inlcuded in + // We should check that hostKey algorithm is included in // algorithms.HostKeys. HostKeyAlgorithms: algorithms.HostKeys, } diff --git a/ssh/handshake_test.go b/ssh/handshake_test.go index 61f978491f..56f230cae9 100644 --- a/ssh/handshake_test.go +++ b/ssh/handshake_test.go @@ -1330,7 +1330,7 @@ func TestAlgorithmNegotiationError(t *testing.T) { _, _, _, err = NewClientConn(c2, "", clientConf) if err == nil { - t.Fatal("client connection succeded expected algorithm negotiation error") + t.Fatal("client connection succeeded expected algorithm negotiation error") } var negotiationError *AlgorithmNegotiationError if !errors.As(err, &negotiationError) { diff --git a/ssh/server_test.go b/ssh/server_test.go index e48f7e3059..e1861931db 100644 --- a/ssh/server_test.go +++ b/ssh/server_test.go @@ -724,7 +724,7 @@ func TestVerifiedPublicCallbackPartialSuccessBadUsage(t *testing.T) { _, _, _, err = NewClientConn(c2, "", &clientConf) if err == nil { - t.Fatal("authentication suceeded with PartialSuccess returned from PublicKeyCallback and VerifiedPublicKeyCallback defined") + t.Fatal("authentication succeeded with PartialSuccess returned from PublicKeyCallback and VerifiedPublicKeyCallback defined") } } @@ -803,7 +803,7 @@ func TestVerifiedPublicKeyCallbackOnly(t *testing.T) { _, _, _, err = NewClientConn(c2, "", &clientConf) if err == nil { - t.Fatal("authentication suceeded with only VerifiedPublicKeyCallback defined") + t.Fatal("authentication succeeded with only VerifiedPublicKeyCallback defined") } <-done } diff --git a/ssh/test/recording_client_test.go b/ssh/test/recording_client_test.go index 5c7830f92a..b744bd332e 100644 --- a/ssh/test/recording_client_test.go +++ b/ssh/test/recording_client_test.go @@ -251,7 +251,7 @@ func TestClientKeyExchanges(t *testing.T) { var keyExchanges []string for _, kex := range config.KeyExchanges { - // Exclude ecdh for now, to make them determistic we should use see a + // Exclude ecdh for now, to make them deterministic we should use see a // stream of fixed bytes as the random source. if !strings.HasPrefix(kex, "ecdh-") { keyExchanges = append(keyExchanges, kex) diff --git a/ssh/test/recording_server_test.go b/ssh/test/recording_server_test.go index fe991986d3..898a8478e5 100644 --- a/ssh/test/recording_server_test.go +++ b/ssh/test/recording_server_test.go @@ -232,7 +232,7 @@ func TestServerKeyExchanges(t *testing.T) { var keyExchanges []string for _, kex := range config.KeyExchanges { - // Exclude ecdh for now, to make them determistic we should use see a + // Exclude ecdh for now, to make them deterministic we should use see a // stream of fixed bytes as the random source. // Exclude ML-KEM because server side is not deterministic. if !strings.HasPrefix(kex, "ecdh-") && !strings.HasPrefix(kex, "mlkem") { diff --git a/x509roots/nss/parser.go b/x509roots/nss/parser.go index feca766e18..5c9f36a651 100644 --- a/x509roots/nss/parser.go +++ b/x509roots/nss/parser.go @@ -192,7 +192,7 @@ func Parse(r io.Reader) ([]*Certificate, error) { // Since we only really care about a couple of fields, this parser throws // away a lot of information, essentially just consuming CKA_CLASS objects // and looking for the individual fields we care about. We could write a - // siginificantly more complex parser, which handles the entire format, but + // significantly more complex parser, which handles the entire format, but // it feels like that would be over engineered for the little information // that we really care about. From 0b7aa0cfb07b6b13ead990b67cb3cb8639871f90 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Sun, 5 Oct 2025 15:42:14 +0800 Subject: [PATCH 25/37] ssh: use reflect.TypeFor instead of reflect.TypeOf For golang/go#60088. Change-Id: I58994c469a2793516214ab1a0072fb6137afc46e Reviewed-on: https://go-review.googlesource.com/c/crypto/+/709156 Auto-Submit: Sean Liao LUCI-TryBot-Result: Go LUCI Reviewed-by: Nicola Murino Reviewed-by: Michael Pratt Reviewed-by: Carlos Amedee Reviewed-by: Sean Liao --- ssh/messages.go | 2 +- ssh/messages_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ssh/messages.go b/ssh/messages.go index 251b9d06a3..ab22c3d38d 100644 --- a/ssh/messages.go +++ b/ssh/messages.go @@ -792,7 +792,7 @@ func marshalString(to []byte, s []byte) []byte { return to[len(s):] } -var bigIntType = reflect.TypeOf((*big.Int)(nil)) +var bigIntType = reflect.TypeFor[*big.Int]() // Decode a packet into its corresponding message. func decode(packet []byte) (interface{}, error) { diff --git a/ssh/messages_test.go b/ssh/messages_test.go index d8691bd0ba..ed346285bf 100644 --- a/ssh/messages_test.go +++ b/ssh/messages_test.go @@ -257,7 +257,7 @@ func TestDecode(t *testing.T) { userAuthSuccess, err := decode([]byte{msgUserAuthSuccess}) if err != nil { t.Errorf("error decoding userAuthSuccessMsg") - } else if reflect.TypeOf(userAuthSuccess) != reflect.TypeOf((*userAuthSuccessMsg)(nil)) { + } else if _, ok := userAuthSuccess.(*userAuthSuccessMsg); !ok { t.Errorf("error decoding userAuthSuccessMsg, unexpected %T", userAuthSuccess) } } From cf29fa96f8b66328e59829f064539321159bfa5b Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 8 Oct 2025 14:56:11 +0200 Subject: [PATCH 26/37] sha3: make it mostly a wrapper around crypto/sha3 crypto/sha3 was introduced in Go 1.24, which is now the minimum Go version of this module. Made the hashes go:fix inline wrappers, since the new types can be used as hash.Hash directly. The SHAKE instances need a wrapper for the methods we dropped from crypto.XOF, so no go:fix inline there. Kept the generic implementation for the legacy Keccak hashes we did not bring to the standard library. We need to keep them working, but they don't need to be fast. Fixes golang/go#73681 Updates golang/go#65269 Change-Id: I6a6a69648b6353b153c70a2cec84864e64dcd61b Reviewed-on: https://go-review.googlesource.com/c/crypto/+/710115 LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: David Chase Reviewed-by: Roland Shoemaker --- sha3/_asm/go.mod | 15 - sha3/_asm/go.sum | 12 - sha3/_asm/keccakf_amd64_asm.go | 438 -- sha3/allocations_test.go | 61 - sha3/doc.go | 66 - sha3/hashes.go | 131 +- sha3/hashes_noasm.go | 23 - sha3/keccakf_amd64.go | 13 - sha3/keccakf_amd64.s | 5419 ------------------------ sha3/{sha3.go => legacy_hash.go} | 49 +- sha3/{keccakf.go => legacy_keccakf.go} | 6 +- sha3/sha3_s390x.go | 303 -- sha3/sha3_s390x.s | 33 - sha3/sha3_test.go | 122 - sha3/shake.go | 172 +- sha3/shake_noasm.go | 15 - 16 files changed, 136 insertions(+), 6742 deletions(-) delete mode 100644 sha3/_asm/go.mod delete mode 100644 sha3/_asm/go.sum delete mode 100644 sha3/_asm/keccakf_amd64_asm.go delete mode 100644 sha3/allocations_test.go delete mode 100644 sha3/doc.go delete mode 100644 sha3/hashes_noasm.go delete mode 100644 sha3/keccakf_amd64.go delete mode 100644 sha3/keccakf_amd64.s rename sha3/{sha3.go => legacy_hash.go} (83%) rename sha3/{keccakf.go => legacy_keccakf.go} (98%) delete mode 100644 sha3/sha3_s390x.go delete mode 100644 sha3/sha3_s390x.s delete mode 100644 sha3/shake_noasm.go diff --git a/sha3/_asm/go.mod b/sha3/_asm/go.mod deleted file mode 100644 index cd16c586a9..0000000000 --- a/sha3/_asm/go.mod +++ /dev/null @@ -1,15 +0,0 @@ -module sha3/_asm - -go 1.22 - -require ( - github.com/mmcloughlin/avo v0.6.0 - golang.org/x/crypto v0.33.0 -) - -require ( - golang.org/x/mod v0.19.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/tools v0.23.0 // indirect -) diff --git a/sha3/_asm/go.sum b/sha3/_asm/go.sum deleted file mode 100644 index 6083f86740..0000000000 --- a/sha3/_asm/go.sum +++ /dev/null @@ -1,12 +0,0 @@ -github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= -github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= diff --git a/sha3/_asm/keccakf_amd64_asm.go b/sha3/_asm/keccakf_amd64_asm.go deleted file mode 100644 index 78e931f757..0000000000 --- a/sha3/_asm/keccakf_amd64_asm.go +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2024 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This code was translated into a form compatible with 6a from the public -// domain sources at https://github.com/gvanas/KeccakCodePackage - -package main - -import ( - . "github.com/mmcloughlin/avo/build" - . "github.com/mmcloughlin/avo/operand" - . "github.com/mmcloughlin/avo/reg" - _ "golang.org/x/crypto/sha3" -) - -//go:generate go run . -out ../keccakf_amd64.s -pkg sha3 - -// Round Constants for use in the ι step. -var RoundConstants = [24]uint64{ - 0x0000000000000001, - 0x0000000000008082, - 0x800000000000808A, - 0x8000000080008000, - 0x000000000000808B, - 0x0000000080000001, - 0x8000000080008081, - 0x8000000000008009, - 0x000000000000008A, - 0x0000000000000088, - 0x0000000080008009, - 0x000000008000000A, - 0x000000008000808B, - 0x800000000000008B, - 0x8000000000008089, - 0x8000000000008003, - 0x8000000000008002, - 0x8000000000000080, - 0x000000000000800A, - 0x800000008000000A, - 0x8000000080008081, - 0x8000000000008080, - 0x0000000080000001, - 0x8000000080008008, -} - -var ( - // Temporary registers - rT1 GPPhysical = RAX - - // Round vars - rpState = Mem{Base: RDI} - rpStack = Mem{Base: RSP} - - rDa = RBX - rDe = RCX - rDi = RDX - rDo = R8 - rDu = R9 - - rBa = R10 - rBe = R11 - rBi = R12 - rBo = R13 - rBu = R14 - - rCa = RSI - rCe = RBP - rCi = rBi - rCo = rBo - rCu = R15 -) - -const ( - _ba = iota * 8 - _be - _bi - _bo - _bu - _ga - _ge - _gi - _go - _gu - _ka - _ke - _ki - _ko - _ku - _ma - _me - _mi - _mo - _mu - _sa - _se - _si - _so - _su -) - -func main() { - Package("golang.org/x/crypto/sha3") - ConstraintExpr("amd64,!purego,gc") - keccakF1600() - Generate() -} - -func MOVQ_RBI_RCE() { MOVQ(rBi, rCe) } -func XORQ_RT1_RCA() { XORQ(rT1, rCa) } -func XORQ_RT1_RCE() { XORQ(rT1, rCe) } -func XORQ_RBA_RCU() { XORQ(rBa, rCu) } -func XORQ_RBE_RCU() { XORQ(rBe, rCu) } -func XORQ_RDU_RCU() { XORQ(rDu, rCu) } -func XORQ_RDA_RCA() { XORQ(rDa, rCa) } -func XORQ_RDE_RCE() { XORQ(rDe, rCe) } - -type ArgMacro func() - -func mKeccakRound( - iState, oState Mem, - rc U64, - B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, - K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, - M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, - S_RDE_RCE ArgMacro, -) { - Comment("Prepare round") - MOVQ(rCe, rDa) - ROLQ(Imm(1), rDa) - - MOVQ(iState.Offset(_bi), rCi) - XORQ(iState.Offset(_gi), rDi) - XORQ(rCu, rDa) - XORQ(iState.Offset(_ki), rCi) - XORQ(iState.Offset(_mi), rDi) - XORQ(rDi, rCi) - - MOVQ(rCi, rDe) - ROLQ(Imm(1), rDe) - - MOVQ(iState.Offset(_bo), rCo) - XORQ(iState.Offset(_go), rDo) - XORQ(rCa, rDe) - XORQ(iState.Offset(_ko), rCo) - XORQ(iState.Offset(_mo), rDo) - XORQ(rDo, rCo) - - MOVQ(rCo, rDi) - ROLQ(Imm(1), rDi) - - MOVQ(rCu, rDo) - XORQ(rCe, rDi) - ROLQ(Imm(1), rDo) - - MOVQ(rCa, rDu) - XORQ(rCi, rDo) - ROLQ(Imm(1), rDu) - - Comment("Result b") - MOVQ(iState.Offset(_ba), rBa) - MOVQ(iState.Offset(_ge), rBe) - XORQ(rCo, rDu) - MOVQ(iState.Offset(_ki), rBi) - MOVQ(iState.Offset(_mo), rBo) - MOVQ(iState.Offset(_su), rBu) - XORQ(rDe, rBe) - ROLQ(Imm(44), rBe) - XORQ(rDi, rBi) - XORQ(rDa, rBa) - ROLQ(Imm(43), rBi) - - MOVQ(rBe, rCa) - MOVQ(rc, rT1) - ORQ(rBi, rCa) - XORQ(rBa, rT1) - XORQ(rT1, rCa) - MOVQ(rCa, oState.Offset(_ba)) - - XORQ(rDu, rBu) - ROLQ(Imm(14), rBu) - MOVQ(rBa, rCu) - ANDQ(rBe, rCu) - XORQ(rBu, rCu) - MOVQ(rCu, oState.Offset(_bu)) - - XORQ(rDo, rBo) - ROLQ(Imm(21), rBo) - MOVQ(rBo, rT1) - ANDQ(rBu, rT1) - XORQ(rBi, rT1) - MOVQ(rT1, oState.Offset(_bi)) - - NOTQ(rBi) - ORQ(rBa, rBu) - ORQ(rBo, rBi) - XORQ(rBo, rBu) - XORQ(rBe, rBi) - MOVQ(rBu, oState.Offset(_bo)) - MOVQ(rBi, oState.Offset(_be)) - B_RBI_RCE() - - Comment("Result g") - MOVQ(iState.Offset(_gu), rBe) - XORQ(rDu, rBe) - MOVQ(iState.Offset(_ka), rBi) - ROLQ(Imm(20), rBe) - XORQ(rDa, rBi) - ROLQ(Imm(3), rBi) - MOVQ(iState.Offset(_bo), rBa) - MOVQ(rBe, rT1) - ORQ(rBi, rT1) - XORQ(rDo, rBa) - MOVQ(iState.Offset(_me), rBo) - MOVQ(iState.Offset(_si), rBu) - ROLQ(Imm(28), rBa) - XORQ(rBa, rT1) - MOVQ(rT1, oState.Offset(_ga)) - G_RT1_RCA() - - XORQ(rDe, rBo) - ROLQ(Imm(45), rBo) - MOVQ(rBi, rT1) - ANDQ(rBo, rT1) - XORQ(rBe, rT1) - MOVQ(rT1, oState.Offset(_ge)) - G_RT1_RCE() - - XORQ(rDi, rBu) - ROLQ(Imm(61), rBu) - MOVQ(rBu, rT1) - ORQ(rBa, rT1) - XORQ(rBo, rT1) - MOVQ(rT1, oState.Offset(_go)) - - ANDQ(rBe, rBa) - XORQ(rBu, rBa) - MOVQ(rBa, oState.Offset(_gu)) - NOTQ(rBu) - G_RBA_RCU() - - ORQ(rBu, rBo) - XORQ(rBi, rBo) - MOVQ(rBo, oState.Offset(_gi)) - - Comment("Result k") - MOVQ(iState.Offset(_be), rBa) - MOVQ(iState.Offset(_gi), rBe) - MOVQ(iState.Offset(_ko), rBi) - MOVQ(iState.Offset(_mu), rBo) - MOVQ(iState.Offset(_sa), rBu) - XORQ(rDi, rBe) - ROLQ(Imm(6), rBe) - XORQ(rDo, rBi) - ROLQ(Imm(25), rBi) - MOVQ(rBe, rT1) - ORQ(rBi, rT1) - XORQ(rDe, rBa) - ROLQ(Imm(1), rBa) - XORQ(rBa, rT1) - MOVQ(rT1, oState.Offset(_ka)) - K_RT1_RCA() - - XORQ(rDu, rBo) - ROLQ(Imm(8), rBo) - MOVQ(rBi, rT1) - ANDQ(rBo, rT1) - XORQ(rBe, rT1) - MOVQ(rT1, oState.Offset(_ke)) - K_RT1_RCE() - - XORQ(rDa, rBu) - ROLQ(Imm(18), rBu) - NOTQ(rBo) - MOVQ(rBo, rT1) - ANDQ(rBu, rT1) - XORQ(rBi, rT1) - MOVQ(rT1, oState.Offset(_ki)) - - MOVQ(rBu, rT1) - ORQ(rBa, rT1) - XORQ(rBo, rT1) - MOVQ(rT1, oState.Offset(_ko)) - - ANDQ(rBe, rBa) - XORQ(rBu, rBa) - MOVQ(rBa, oState.Offset(_ku)) - K_RBA_RCU() - - Comment("Result m") - MOVQ(iState.Offset(_ga), rBe) - XORQ(rDa, rBe) - MOVQ(iState.Offset(_ke), rBi) - ROLQ(Imm(36), rBe) - XORQ(rDe, rBi) - MOVQ(iState.Offset(_bu), rBa) - ROLQ(Imm(10), rBi) - MOVQ(rBe, rT1) - MOVQ(iState.Offset(_mi), rBo) - ANDQ(rBi, rT1) - XORQ(rDu, rBa) - MOVQ(iState.Offset(_so), rBu) - ROLQ(Imm(27), rBa) - XORQ(rBa, rT1) - MOVQ(rT1, oState.Offset(_ma)) - M_RT1_RCA() - - XORQ(rDi, rBo) - ROLQ(Imm(15), rBo) - MOVQ(rBi, rT1) - ORQ(rBo, rT1) - XORQ(rBe, rT1) - MOVQ(rT1, oState.Offset(_me)) - M_RT1_RCE() - - XORQ(rDo, rBu) - ROLQ(Imm(56), rBu) - NOTQ(rBo) - MOVQ(rBo, rT1) - ORQ(rBu, rT1) - XORQ(rBi, rT1) - MOVQ(rT1, oState.Offset(_mi)) - - ORQ(rBa, rBe) - XORQ(rBu, rBe) - MOVQ(rBe, oState.Offset(_mu)) - - ANDQ(rBa, rBu) - XORQ(rBo, rBu) - MOVQ(rBu, oState.Offset(_mo)) - M_RBE_RCU() - - Comment("Result s") - MOVQ(iState.Offset(_bi), rBa) - MOVQ(iState.Offset(_go), rBe) - MOVQ(iState.Offset(_ku), rBi) - XORQ(rDi, rBa) - MOVQ(iState.Offset(_ma), rBo) - ROLQ(Imm(62), rBa) - XORQ(rDo, rBe) - MOVQ(iState.Offset(_se), rBu) - ROLQ(Imm(55), rBe) - - XORQ(rDu, rBi) - MOVQ(rBa, rDu) - XORQ(rDe, rBu) - ROLQ(Imm(2), rBu) - ANDQ(rBe, rDu) - XORQ(rBu, rDu) - MOVQ(rDu, oState.Offset(_su)) - - ROLQ(Imm(39), rBi) - S_RDU_RCU() - NOTQ(rBe) - XORQ(rDa, rBo) - MOVQ(rBe, rDa) - ANDQ(rBi, rDa) - XORQ(rBa, rDa) - MOVQ(rDa, oState.Offset(_sa)) - S_RDA_RCA() - - ROLQ(Imm(41), rBo) - MOVQ(rBi, rDe) - ORQ(rBo, rDe) - XORQ(rBe, rDe) - MOVQ(rDe, oState.Offset(_se)) - S_RDE_RCE() - - MOVQ(rBo, rDi) - MOVQ(rBu, rDo) - ANDQ(rBu, rDi) - ORQ(rBa, rDo) - XORQ(rBi, rDi) - XORQ(rBo, rDo) - MOVQ(rDi, oState.Offset(_si)) - MOVQ(rDo, oState.Offset(_so)) -} - -// keccakF1600 applies the Keccak permutation to a 1600b-wide -// state represented as a slice of 25 uint64s. -func keccakF1600() { - Implement("keccakF1600") - AllocLocal(200) - - Load(Param("a"), rpState.Base) - - Comment("Convert the user state into an internal state") - NOTQ(rpState.Offset(_be)) - NOTQ(rpState.Offset(_bi)) - NOTQ(rpState.Offset(_go)) - NOTQ(rpState.Offset(_ki)) - NOTQ(rpState.Offset(_mi)) - NOTQ(rpState.Offset(_sa)) - - Comment("Execute the KeccakF permutation") - MOVQ(rpState.Offset(_ba), rCa) - MOVQ(rpState.Offset(_be), rCe) - MOVQ(rpState.Offset(_bu), rCu) - - XORQ(rpState.Offset(_ga), rCa) - XORQ(rpState.Offset(_ge), rCe) - XORQ(rpState.Offset(_gu), rCu) - - XORQ(rpState.Offset(_ka), rCa) - XORQ(rpState.Offset(_ke), rCe) - XORQ(rpState.Offset(_ku), rCu) - - XORQ(rpState.Offset(_ma), rCa) - XORQ(rpState.Offset(_me), rCe) - XORQ(rpState.Offset(_mu), rCu) - - XORQ(rpState.Offset(_sa), rCa) - XORQ(rpState.Offset(_se), rCe) - MOVQ(rpState.Offset(_si), rDi) - MOVQ(rpState.Offset(_so), rDo) - XORQ(rpState.Offset(_su), rCu) - - for i, rc := range RoundConstants[:len(RoundConstants)-1] { - var iState, oState Mem - if i%2 == 0 { - iState, oState = rpState, rpStack - } else { - iState, oState = rpStack, rpState - } - mKeccakRound(iState, oState, U64(rc), MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) - } - mKeccakRound(rpStack, rpState, U64(RoundConstants[len(RoundConstants)-1]), NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP) - - Comment("Revert the internal state to the user state") - NOTQ(rpState.Offset(_be)) - NOTQ(rpState.Offset(_bi)) - NOTQ(rpState.Offset(_go)) - NOTQ(rpState.Offset(_ki)) - NOTQ(rpState.Offset(_mi)) - NOTQ(rpState.Offset(_sa)) - - RET() -} diff --git a/sha3/allocations_test.go b/sha3/allocations_test.go deleted file mode 100644 index 36de5d547e..0000000000 --- a/sha3/allocations_test.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !noopt - -package sha3_test - -import ( - "runtime" - "testing" - - "golang.org/x/crypto/sha3" -) - -var sink byte - -func TestAllocations(t *testing.T) { - want := 0.0 - - if runtime.GOARCH == "s390x" { - // On s390x the returned hash.Hash is conditional so it escapes. - want = 3.0 - } - - t.Run("New", func(t *testing.T) { - if allocs := testing.AllocsPerRun(10, func() { - h := sha3.New256() - b := []byte("ABC") - h.Write(b) - out := make([]byte, 0, 32) - out = h.Sum(out) - sink ^= out[0] - }); allocs > want { - t.Errorf("expected zero allocations, got %0.1f", allocs) - } - }) - t.Run("NewShake", func(t *testing.T) { - if allocs := testing.AllocsPerRun(10, func() { - h := sha3.NewShake128() - b := []byte("ABC") - h.Write(b) - out := make([]byte, 0, 32) - out = h.Sum(out) - sink ^= out[0] - h.Read(out) - sink ^= out[0] - }); allocs > want { - t.Errorf("expected zero allocations, got %0.1f", allocs) - } - }) - t.Run("Sum", func(t *testing.T) { - if allocs := testing.AllocsPerRun(10, func() { - b := []byte("ABC") - out := sha3.Sum256(b) - sink ^= out[0] - }); allocs > want { - t.Errorf("expected zero allocations, got %0.1f", allocs) - } - }) -} diff --git a/sha3/doc.go b/sha3/doc.go deleted file mode 100644 index bbf391fe6e..0000000000 --- a/sha3/doc.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package sha3 implements the SHA-3 fixed-output-length hash functions and -// the SHAKE variable-output-length hash functions defined by FIPS-202. -// -// All types in this package also implement [encoding.BinaryMarshaler], -// [encoding.BinaryAppender] and [encoding.BinaryUnmarshaler] to marshal and -// unmarshal the internal state of the hash. -// -// Both types of hash function use the "sponge" construction and the Keccak -// permutation. For a detailed specification see http://keccak.noekeon.org/ -// -// # Guidance -// -// If you aren't sure what function you need, use SHAKE256 with at least 64 -// bytes of output. The SHAKE instances are faster than the SHA3 instances; -// the latter have to allocate memory to conform to the hash.Hash interface. -// -// If you need a secret-key MAC (message authentication code), prepend the -// secret key to the input, hash with SHAKE256 and read at least 32 bytes of -// output. -// -// # Security strengths -// -// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security -// strength against preimage attacks of x bits. Since they only produce "x" -// bits of output, their collision-resistance is only "x/2" bits. -// -// The SHAKE-256 and -128 functions have a generic security strength of 256 and -// 128 bits against all attacks, provided that at least 2x bits of their output -// is used. Requesting more than 64 or 32 bytes of output, respectively, does -// not increase the collision-resistance of the SHAKE functions. -// -// # The sponge construction -// -// A sponge builds a pseudo-random function from a public pseudo-random -// permutation, by applying the permutation to a state of "rate + capacity" -// bytes, but hiding "capacity" of the bytes. -// -// A sponge starts out with a zero state. To hash an input using a sponge, up -// to "rate" bytes of the input are XORed into the sponge's state. The sponge -// is then "full" and the permutation is applied to "empty" it. This process is -// repeated until all the input has been "absorbed". The input is then padded. -// The digest is "squeezed" from the sponge in the same way, except that output -// is copied out instead of input being XORed in. -// -// A sponge is parameterized by its generic security strength, which is equal -// to half its capacity; capacity + rate is equal to the permutation's width. -// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means -// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. -// -// # Recommendations -// -// The SHAKE functions are recommended for most new uses. They can produce -// output of arbitrary length. SHAKE256, with an output length of at least -// 64 bytes, provides 256-bit security against all attacks. The Keccak team -// recommends it for most applications upgrading from SHA2-512. (NIST chose a -// much stronger, but much slower, sponge instance for SHA3-512.) -// -// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions. -// They produce output of the same length, with the same security strengths -// against all attacks. This means, in particular, that SHA3-256 only has -// 128-bit collision resistance, because its output length is 32 bytes. -package sha3 diff --git a/sha3/hashes.go b/sha3/hashes.go index 31fffbe044..a51269d91a 100644 --- a/sha3/hashes.go +++ b/sha3/hashes.go @@ -2,127 +2,94 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Package sha3 implements the SHA-3 hash algorithms and the SHAKE extendable +// output functions defined in FIPS 202. +// +// Most of this package is a wrapper around the crypto/sha3 package in the +// standard library. The only exception is the legacy Keccak hash functions. package sha3 -// This file provides functions for creating instances of the SHA-3 -// and SHAKE hash functions, as well as utility functions for hashing -// bytes. - import ( - "crypto" + "crypto/sha3" "hash" ) // New224 creates a new SHA3-224 hash. // Its generic security strength is 224 bits against preimage attacks, // and 112 bits against collision attacks. +// +// It is a wrapper for the [sha3.New224] function in the standard library. +// +//go:fix inline func New224() hash.Hash { - return new224() + return sha3.New224() } // New256 creates a new SHA3-256 hash. // Its generic security strength is 256 bits against preimage attacks, // and 128 bits against collision attacks. +// +// It is a wrapper for the [sha3.New256] function in the standard library. +// +//go:fix inline func New256() hash.Hash { - return new256() + return sha3.New256() } // New384 creates a new SHA3-384 hash. // Its generic security strength is 384 bits against preimage attacks, // and 192 bits against collision attacks. +// +// It is a wrapper for the [sha3.New384] function in the standard library. +// +//go:fix inline func New384() hash.Hash { - return new384() + return sha3.New384() } // New512 creates a new SHA3-512 hash. // Its generic security strength is 512 bits against preimage attacks, // and 256 bits against collision attacks. -func New512() hash.Hash { - return new512() -} - -func init() { - crypto.RegisterHash(crypto.SHA3_224, New224) - crypto.RegisterHash(crypto.SHA3_256, New256) - crypto.RegisterHash(crypto.SHA3_384, New384) - crypto.RegisterHash(crypto.SHA3_512, New512) -} - -const ( - dsbyteSHA3 = 0b00000110 - dsbyteKeccak = 0b00000001 - dsbyteShake = 0b00011111 - dsbyteCShake = 0b00000100 - - // rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in - // bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits. - rateK256 = (1600 - 256) / 8 - rateK448 = (1600 - 448) / 8 - rateK512 = (1600 - 512) / 8 - rateK768 = (1600 - 768) / 8 - rateK1024 = (1600 - 1024) / 8 -) - -func new224Generic() *state { - return &state{rate: rateK448, outputLen: 28, dsbyte: dsbyteSHA3} -} - -func new256Generic() *state { - return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteSHA3} -} - -func new384Generic() *state { - return &state{rate: rateK768, outputLen: 48, dsbyte: dsbyteSHA3} -} - -func new512Generic() *state { - return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteSHA3} -} - -// NewLegacyKeccak256 creates a new Keccak-256 hash. // -// Only use this function if you require compatibility with an existing cryptosystem -// that uses non-standard padding. All other users should use New256 instead. -func NewLegacyKeccak256() hash.Hash { - return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak} -} - -// NewLegacyKeccak512 creates a new Keccak-512 hash. +// It is a wrapper for the [sha3.New512] function in the standard library. // -// Only use this function if you require compatibility with an existing cryptosystem -// that uses non-standard padding. All other users should use New512 instead. -func NewLegacyKeccak512() hash.Hash { - return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak} +//go:fix inline +func New512() hash.Hash { + return sha3.New512() } // Sum224 returns the SHA3-224 digest of the data. -func Sum224(data []byte) (digest [28]byte) { - h := New224() - h.Write(data) - h.Sum(digest[:0]) - return +// +// It is a wrapper for the [sha3.Sum224] function in the standard library. +// +//go:fix inline +func Sum224(data []byte) [28]byte { + return sha3.Sum224(data) } // Sum256 returns the SHA3-256 digest of the data. -func Sum256(data []byte) (digest [32]byte) { - h := New256() - h.Write(data) - h.Sum(digest[:0]) - return +// +// It is a wrapper for the [sha3.Sum256] function in the standard library. +// +//go:fix inline +func Sum256(data []byte) [32]byte { + return sha3.Sum256(data) } // Sum384 returns the SHA3-384 digest of the data. -func Sum384(data []byte) (digest [48]byte) { - h := New384() - h.Write(data) - h.Sum(digest[:0]) - return +// +// It is a wrapper for the [sha3.Sum384] function in the standard library. +// +//go:fix inline +func Sum384(data []byte) [48]byte { + return sha3.Sum384(data) } // Sum512 returns the SHA3-512 digest of the data. -func Sum512(data []byte) (digest [64]byte) { - h := New512() - h.Write(data) - h.Sum(digest[:0]) - return +// +// It is a wrapper for the [sha3.Sum512] function in the standard library. +// +//go:fix inline +func Sum512(data []byte) [64]byte { + return sha3.Sum512(data) } diff --git a/sha3/hashes_noasm.go b/sha3/hashes_noasm.go deleted file mode 100644 index 9d85fb6214..0000000000 --- a/sha3/hashes_noasm.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !gc || purego || !s390x - -package sha3 - -func new224() *state { - return new224Generic() -} - -func new256() *state { - return new256Generic() -} - -func new384() *state { - return new384Generic() -} - -func new512() *state { - return new512Generic() -} diff --git a/sha3/keccakf_amd64.go b/sha3/keccakf_amd64.go deleted file mode 100644 index b908696be5..0000000000 --- a/sha3/keccakf_amd64.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build amd64 && !purego && gc - -package sha3 - -// This function is implemented in keccakf_amd64.s. - -//go:noescape - -func keccakF1600(a *[25]uint64) diff --git a/sha3/keccakf_amd64.s b/sha3/keccakf_amd64.s deleted file mode 100644 index 99e2f16e97..0000000000 --- a/sha3/keccakf_amd64.s +++ /dev/null @@ -1,5419 +0,0 @@ -// Code generated by command: go run keccakf_amd64_asm.go -out ../keccakf_amd64.s -pkg sha3. DO NOT EDIT. - -//go:build amd64 && !purego && gc - -// func keccakF1600(a *[25]uint64) -TEXT ·keccakF1600(SB), $200-8 - MOVQ a+0(FP), DI - - // Convert the user state into an internal state - NOTQ 8(DI) - NOTQ 16(DI) - NOTQ 64(DI) - NOTQ 96(DI) - NOTQ 136(DI) - NOTQ 160(DI) - - // Execute the KeccakF permutation - MOVQ (DI), SI - MOVQ 8(DI), BP - MOVQ 32(DI), R15 - XORQ 40(DI), SI - XORQ 48(DI), BP - XORQ 72(DI), R15 - XORQ 80(DI), SI - XORQ 88(DI), BP - XORQ 112(DI), R15 - XORQ 120(DI), SI - XORQ 128(DI), BP - XORQ 152(DI), R15 - XORQ 160(DI), SI - XORQ 168(DI), BP - MOVQ 176(DI), DX - MOVQ 184(DI), R8 - XORQ 192(DI), R15 - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x0000000000000001, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x0000000000008082, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x800000000000808a, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000080008000, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x000000000000808b, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x0000000080000001, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000080008081, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000000008009, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x000000000000008a, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x0000000000000088, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x0000000080008009, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x000000008000000a, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x000000008000808b, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x800000000000008b, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000000008089, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000000008003, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000000008002, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000000000080, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x000000000000800a, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x800000008000000a, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000080008081, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000000008080, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - MOVQ R12, BP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - XORQ R10, R15 - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - XORQ R11, R15 - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(DI), R12 - XORQ 56(DI), DX - XORQ R15, BX - XORQ 96(DI), R12 - XORQ 136(DI), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(DI), R13 - XORQ 64(DI), R8 - XORQ SI, CX - XORQ 104(DI), R13 - XORQ 144(DI), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (DI), R10 - MOVQ 48(DI), R11 - XORQ R13, R9 - MOVQ 96(DI), R12 - MOVQ 144(DI), R13 - MOVQ 192(DI), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x0000000080000001, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (SP) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(SP) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(SP) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(SP) - MOVQ R12, 8(SP) - MOVQ R12, BP - - // Result g - MOVQ 72(DI), R11 - XORQ R9, R11 - MOVQ 80(DI), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(DI), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(DI), R13 - MOVQ 176(DI), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(SP) - XORQ AX, SI - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(SP) - XORQ AX, BP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(SP) - NOTQ R14 - XORQ R10, R15 - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(SP) - - // Result k - MOVQ 8(DI), R10 - MOVQ 56(DI), R11 - MOVQ 104(DI), R12 - MOVQ 152(DI), R13 - MOVQ 160(DI), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(SP) - XORQ AX, SI - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(SP) - XORQ AX, BP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(SP) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(SP) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(SP) - XORQ R10, R15 - - // Result m - MOVQ 40(DI), R11 - XORQ BX, R11 - MOVQ 88(DI), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(DI), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(DI), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(DI), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(SP) - XORQ AX, SI - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(SP) - XORQ AX, BP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(SP) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(SP) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(SP) - XORQ R11, R15 - - // Result s - MOVQ 16(DI), R10 - MOVQ 64(DI), R11 - MOVQ 112(DI), R12 - XORQ DX, R10 - MOVQ 120(DI), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(DI), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(SP) - ROLQ $0x27, R12 - XORQ R9, R15 - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(SP) - XORQ BX, SI - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(SP) - XORQ CX, BP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(SP) - MOVQ R8, 184(SP) - - // Prepare round - MOVQ BP, BX - ROLQ $0x01, BX - MOVQ 16(SP), R12 - XORQ 56(SP), DX - XORQ R15, BX - XORQ 96(SP), R12 - XORQ 136(SP), DX - XORQ DX, R12 - MOVQ R12, CX - ROLQ $0x01, CX - MOVQ 24(SP), R13 - XORQ 64(SP), R8 - XORQ SI, CX - XORQ 104(SP), R13 - XORQ 144(SP), R8 - XORQ R8, R13 - MOVQ R13, DX - ROLQ $0x01, DX - MOVQ R15, R8 - XORQ BP, DX - ROLQ $0x01, R8 - MOVQ SI, R9 - XORQ R12, R8 - ROLQ $0x01, R9 - - // Result b - MOVQ (SP), R10 - MOVQ 48(SP), R11 - XORQ R13, R9 - MOVQ 96(SP), R12 - MOVQ 144(SP), R13 - MOVQ 192(SP), R14 - XORQ CX, R11 - ROLQ $0x2c, R11 - XORQ DX, R12 - XORQ BX, R10 - ROLQ $0x2b, R12 - MOVQ R11, SI - MOVQ $0x8000000080008008, AX - ORQ R12, SI - XORQ R10, AX - XORQ AX, SI - MOVQ SI, (DI) - XORQ R9, R14 - ROLQ $0x0e, R14 - MOVQ R10, R15 - ANDQ R11, R15 - XORQ R14, R15 - MOVQ R15, 32(DI) - XORQ R8, R13 - ROLQ $0x15, R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 16(DI) - NOTQ R12 - ORQ R10, R14 - ORQ R13, R12 - XORQ R13, R14 - XORQ R11, R12 - MOVQ R14, 24(DI) - MOVQ R12, 8(DI) - NOP - - // Result g - MOVQ 72(SP), R11 - XORQ R9, R11 - MOVQ 80(SP), R12 - ROLQ $0x14, R11 - XORQ BX, R12 - ROLQ $0x03, R12 - MOVQ 24(SP), R10 - MOVQ R11, AX - ORQ R12, AX - XORQ R8, R10 - MOVQ 128(SP), R13 - MOVQ 176(SP), R14 - ROLQ $0x1c, R10 - XORQ R10, AX - MOVQ AX, 40(DI) - NOP - XORQ CX, R13 - ROLQ $0x2d, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 48(DI) - NOP - XORQ DX, R14 - ROLQ $0x3d, R14 - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 64(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 72(DI) - NOTQ R14 - NOP - ORQ R14, R13 - XORQ R12, R13 - MOVQ R13, 56(DI) - - // Result k - MOVQ 8(SP), R10 - MOVQ 56(SP), R11 - MOVQ 104(SP), R12 - MOVQ 152(SP), R13 - MOVQ 160(SP), R14 - XORQ DX, R11 - ROLQ $0x06, R11 - XORQ R8, R12 - ROLQ $0x19, R12 - MOVQ R11, AX - ORQ R12, AX - XORQ CX, R10 - ROLQ $0x01, R10 - XORQ R10, AX - MOVQ AX, 80(DI) - NOP - XORQ R9, R13 - ROLQ $0x08, R13 - MOVQ R12, AX - ANDQ R13, AX - XORQ R11, AX - MOVQ AX, 88(DI) - NOP - XORQ BX, R14 - ROLQ $0x12, R14 - NOTQ R13 - MOVQ R13, AX - ANDQ R14, AX - XORQ R12, AX - MOVQ AX, 96(DI) - MOVQ R14, AX - ORQ R10, AX - XORQ R13, AX - MOVQ AX, 104(DI) - ANDQ R11, R10 - XORQ R14, R10 - MOVQ R10, 112(DI) - NOP - - // Result m - MOVQ 40(SP), R11 - XORQ BX, R11 - MOVQ 88(SP), R12 - ROLQ $0x24, R11 - XORQ CX, R12 - MOVQ 32(SP), R10 - ROLQ $0x0a, R12 - MOVQ R11, AX - MOVQ 136(SP), R13 - ANDQ R12, AX - XORQ R9, R10 - MOVQ 184(SP), R14 - ROLQ $0x1b, R10 - XORQ R10, AX - MOVQ AX, 120(DI) - NOP - XORQ DX, R13 - ROLQ $0x0f, R13 - MOVQ R12, AX - ORQ R13, AX - XORQ R11, AX - MOVQ AX, 128(DI) - NOP - XORQ R8, R14 - ROLQ $0x38, R14 - NOTQ R13 - MOVQ R13, AX - ORQ R14, AX - XORQ R12, AX - MOVQ AX, 136(DI) - ORQ R10, R11 - XORQ R14, R11 - MOVQ R11, 152(DI) - ANDQ R10, R14 - XORQ R13, R14 - MOVQ R14, 144(DI) - NOP - - // Result s - MOVQ 16(SP), R10 - MOVQ 64(SP), R11 - MOVQ 112(SP), R12 - XORQ DX, R10 - MOVQ 120(SP), R13 - ROLQ $0x3e, R10 - XORQ R8, R11 - MOVQ 168(SP), R14 - ROLQ $0x37, R11 - XORQ R9, R12 - MOVQ R10, R9 - XORQ CX, R14 - ROLQ $0x02, R14 - ANDQ R11, R9 - XORQ R14, R9 - MOVQ R9, 192(DI) - ROLQ $0x27, R12 - NOP - NOTQ R11 - XORQ BX, R13 - MOVQ R11, BX - ANDQ R12, BX - XORQ R10, BX - MOVQ BX, 160(DI) - NOP - ROLQ $0x29, R13 - MOVQ R12, CX - ORQ R13, CX - XORQ R11, CX - MOVQ CX, 168(DI) - NOP - MOVQ R13, DX - MOVQ R14, R8 - ANDQ R14, DX - ORQ R10, R8 - XORQ R12, DX - XORQ R13, R8 - MOVQ DX, 176(DI) - MOVQ R8, 184(DI) - - // Revert the internal state to the user state - NOTQ 8(DI) - NOTQ 16(DI) - NOTQ 64(DI) - NOTQ 96(DI) - NOTQ 136(DI) - NOTQ 160(DI) - RET diff --git a/sha3/sha3.go b/sha3/legacy_hash.go similarity index 83% rename from sha3/sha3.go rename to sha3/legacy_hash.go index 6658c44479..b8784536e0 100644 --- a/sha3/sha3.go +++ b/sha3/legacy_hash.go @@ -4,15 +4,46 @@ package sha3 +// This implementation is only used for NewLegacyKeccak256 and +// NewLegacyKeccak512, which are not implemented by crypto/sha3. +// All other functions in this package are wrappers around crypto/sha3. + import ( "crypto/subtle" "encoding/binary" "errors" + "hash" "unsafe" "golang.org/x/sys/cpu" ) +const ( + dsbyteKeccak = 0b00000001 + + // rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in + // bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits. + rateK256 = (1600 - 256) / 8 + rateK512 = (1600 - 512) / 8 + rateK1024 = (1600 - 1024) / 8 +) + +// NewLegacyKeccak256 creates a new Keccak-256 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New256 instead. +func NewLegacyKeccak256() hash.Hash { + return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak} +} + +// NewLegacyKeccak512 creates a new Keccak-512 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New512 instead. +func NewLegacyKeccak512() hash.Hash { + return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak} +} + // spongeDirection indicates the direction bytes are flowing through the sponge. type spongeDirection int @@ -173,12 +204,9 @@ func (d *state) Sum(in []byte) []byte { } const ( - magicSHA3 = "sha\x08" - magicShake = "sha\x09" - magicCShake = "sha\x0a" magicKeccak = "sha\x0b" // magic || rate || main state || n || sponge direction - marshaledSize = len(magicSHA3) + 1 + 200 + 1 + 1 + marshaledSize = len(magicKeccak) + 1 + 200 + 1 + 1 ) func (d *state) MarshalBinary() ([]byte, error) { @@ -187,12 +215,6 @@ func (d *state) MarshalBinary() ([]byte, error) { func (d *state) AppendBinary(b []byte) ([]byte, error) { switch d.dsbyte { - case dsbyteSHA3: - b = append(b, magicSHA3...) - case dsbyteShake: - b = append(b, magicShake...) - case dsbyteCShake: - b = append(b, magicCShake...) case dsbyteKeccak: b = append(b, magicKeccak...) default: @@ -210,12 +232,9 @@ func (d *state) UnmarshalBinary(b []byte) error { return errors.New("sha3: invalid hash state") } - magic := string(b[:len(magicSHA3)]) - b = b[len(magicSHA3):] + magic := string(b[:len(magicKeccak)]) + b = b[len(magicKeccak):] switch { - case magic == magicSHA3 && d.dsbyte == dsbyteSHA3: - case magic == magicShake && d.dsbyte == dsbyteShake: - case magic == magicCShake && d.dsbyte == dsbyteCShake: case magic == magicKeccak && d.dsbyte == dsbyteKeccak: default: return errors.New("sha3: invalid hash state identifier") diff --git a/sha3/keccakf.go b/sha3/legacy_keccakf.go similarity index 98% rename from sha3/keccakf.go rename to sha3/legacy_keccakf.go index ce48b1dd3e..101588c16c 100644 --- a/sha3/keccakf.go +++ b/sha3/legacy_keccakf.go @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 || purego || !gc - package sha3 +// This implementation is only used for NewLegacyKeccak256 and +// NewLegacyKeccak512, which are not implemented by crypto/sha3. +// All other functions in this package are wrappers around crypto/sha3. + import "math/bits" // rc stores the round constants for use in the ι step. diff --git a/sha3/sha3_s390x.go b/sha3/sha3_s390x.go deleted file mode 100644 index 00d8034ae6..0000000000 --- a/sha3/sha3_s390x.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego - -package sha3 - -// This file contains code for using the 'compute intermediate -// message digest' (KIMD) and 'compute last message digest' (KLMD) -// instructions to compute SHA-3 and SHAKE hashes on IBM Z. - -import ( - "hash" - - "golang.org/x/sys/cpu" -) - -// codes represent 7-bit KIMD/KLMD function codes as defined in -// the Principles of Operation. -type code uint64 - -const ( - // function codes for KIMD/KLMD - sha3_224 code = 32 - sha3_256 = 33 - sha3_384 = 34 - sha3_512 = 35 - shake_128 = 36 - shake_256 = 37 - nopad = 0x100 -) - -// kimd is a wrapper for the 'compute intermediate message digest' instruction. -// src must be a multiple of the rate for the given function code. -// -//go:noescape -func kimd(function code, chain *[200]byte, src []byte) - -// klmd is a wrapper for the 'compute last message digest' instruction. -// src padding is handled by the instruction. -// -//go:noescape -func klmd(function code, chain *[200]byte, dst, src []byte) - -type asmState struct { - a [200]byte // 1600 bit state - buf []byte // care must be taken to ensure cap(buf) is a multiple of rate - rate int // equivalent to block size - storage [3072]byte // underlying storage for buf - outputLen int // output length for full security - function code // KIMD/KLMD function code - state spongeDirection // whether the sponge is absorbing or squeezing -} - -func newAsmState(function code) *asmState { - var s asmState - s.function = function - switch function { - case sha3_224: - s.rate = 144 - s.outputLen = 28 - case sha3_256: - s.rate = 136 - s.outputLen = 32 - case sha3_384: - s.rate = 104 - s.outputLen = 48 - case sha3_512: - s.rate = 72 - s.outputLen = 64 - case shake_128: - s.rate = 168 - s.outputLen = 32 - case shake_256: - s.rate = 136 - s.outputLen = 64 - default: - panic("sha3: unrecognized function code") - } - - // limit s.buf size to a multiple of s.rate - s.resetBuf() - return &s -} - -func (s *asmState) clone() *asmState { - c := *s - c.buf = c.storage[:len(s.buf):cap(s.buf)] - return &c -} - -// copyIntoBuf copies b into buf. It will panic if there is not enough space to -// store all of b. -func (s *asmState) copyIntoBuf(b []byte) { - bufLen := len(s.buf) - s.buf = s.buf[:len(s.buf)+len(b)] - copy(s.buf[bufLen:], b) -} - -// resetBuf points buf at storage, sets the length to 0 and sets cap to be a -// multiple of the rate. -func (s *asmState) resetBuf() { - max := (cap(s.storage) / s.rate) * s.rate - s.buf = s.storage[:0:max] -} - -// Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. -func (s *asmState) Write(b []byte) (int, error) { - if s.state != spongeAbsorbing { - panic("sha3: Write after Read") - } - length := len(b) - for len(b) > 0 { - if len(s.buf) == 0 && len(b) >= cap(s.buf) { - // Hash the data directly and push any remaining bytes - // into the buffer. - remainder := len(b) % s.rate - kimd(s.function, &s.a, b[:len(b)-remainder]) - if remainder != 0 { - s.copyIntoBuf(b[len(b)-remainder:]) - } - return length, nil - } - - if len(s.buf) == cap(s.buf) { - // flush the buffer - kimd(s.function, &s.a, s.buf) - s.buf = s.buf[:0] - } - - // copy as much as we can into the buffer - n := len(b) - if len(b) > cap(s.buf)-len(s.buf) { - n = cap(s.buf) - len(s.buf) - } - s.copyIntoBuf(b[:n]) - b = b[n:] - } - return length, nil -} - -// Read squeezes an arbitrary number of bytes from the sponge. -func (s *asmState) Read(out []byte) (n int, err error) { - // The 'compute last message digest' instruction only stores the digest - // at the first operand (dst) for SHAKE functions. - if s.function != shake_128 && s.function != shake_256 { - panic("sha3: can only call Read for SHAKE functions") - } - - n = len(out) - - // need to pad if we were absorbing - if s.state == spongeAbsorbing { - s.state = spongeSqueezing - - // write hash directly into out if possible - if len(out)%s.rate == 0 { - klmd(s.function, &s.a, out, s.buf) // len(out) may be 0 - s.buf = s.buf[:0] - return - } - - // write hash into buffer - max := cap(s.buf) - if max > len(out) { - max = (len(out)/s.rate)*s.rate + s.rate - } - klmd(s.function, &s.a, s.buf[:max], s.buf) - s.buf = s.buf[:max] - } - - for len(out) > 0 { - // flush the buffer - if len(s.buf) != 0 { - c := copy(out, s.buf) - out = out[c:] - s.buf = s.buf[c:] - continue - } - - // write hash directly into out if possible - if len(out)%s.rate == 0 { - klmd(s.function|nopad, &s.a, out, nil) - return - } - - // write hash into buffer - s.resetBuf() - if cap(s.buf) > len(out) { - s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate] - } - klmd(s.function|nopad, &s.a, s.buf, nil) - } - return -} - -// Sum appends the current hash to b and returns the resulting slice. -// It does not change the underlying hash state. -func (s *asmState) Sum(b []byte) []byte { - if s.state != spongeAbsorbing { - panic("sha3: Sum after Read") - } - - // Copy the state to preserve the original. - a := s.a - - // Hash the buffer. Note that we don't clear it because we - // aren't updating the state. - switch s.function { - case sha3_224, sha3_256, sha3_384, sha3_512: - klmd(s.function, &a, nil, s.buf) - return append(b, a[:s.outputLen]...) - case shake_128, shake_256: - d := make([]byte, s.outputLen, 64) - klmd(s.function, &a, d, s.buf) - return append(b, d[:s.outputLen]...) - default: - panic("sha3: unknown function") - } -} - -// Reset resets the Hash to its initial state. -func (s *asmState) Reset() { - for i := range s.a { - s.a[i] = 0 - } - s.resetBuf() - s.state = spongeAbsorbing -} - -// Size returns the number of bytes Sum will return. -func (s *asmState) Size() int { - return s.outputLen -} - -// BlockSize returns the hash's underlying block size. -// The Write method must be able to accept any amount -// of data, but it may operate more efficiently if all writes -// are a multiple of the block size. -func (s *asmState) BlockSize() int { - return s.rate -} - -// Clone returns a copy of the ShakeHash in its current state. -func (s *asmState) Clone() ShakeHash { - return s.clone() -} - -// new224 returns an assembly implementation of SHA3-224 if available, -// otherwise it returns a generic implementation. -func new224() hash.Hash { - if cpu.S390X.HasSHA3 { - return newAsmState(sha3_224) - } - return new224Generic() -} - -// new256 returns an assembly implementation of SHA3-256 if available, -// otherwise it returns a generic implementation. -func new256() hash.Hash { - if cpu.S390X.HasSHA3 { - return newAsmState(sha3_256) - } - return new256Generic() -} - -// new384 returns an assembly implementation of SHA3-384 if available, -// otherwise it returns a generic implementation. -func new384() hash.Hash { - if cpu.S390X.HasSHA3 { - return newAsmState(sha3_384) - } - return new384Generic() -} - -// new512 returns an assembly implementation of SHA3-512 if available, -// otherwise it returns a generic implementation. -func new512() hash.Hash { - if cpu.S390X.HasSHA3 { - return newAsmState(sha3_512) - } - return new512Generic() -} - -// newShake128 returns an assembly implementation of SHAKE-128 if available, -// otherwise it returns a generic implementation. -func newShake128() ShakeHash { - if cpu.S390X.HasSHA3 { - return newAsmState(shake_128) - } - return newShake128Generic() -} - -// newShake256 returns an assembly implementation of SHAKE-256 if available, -// otherwise it returns a generic implementation. -func newShake256() ShakeHash { - if cpu.S390X.HasSHA3 { - return newAsmState(shake_256) - } - return newShake256Generic() -} diff --git a/sha3/sha3_s390x.s b/sha3/sha3_s390x.s deleted file mode 100644 index 826b862c77..0000000000 --- a/sha3/sha3_s390x.s +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego - -#include "textflag.h" - -// func kimd(function code, chain *[200]byte, src []byte) -TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 - MOVD function+0(FP), R0 - MOVD chain+8(FP), R1 - LMG src+16(FP), R2, R3 // R2=base, R3=len - -continue: - WORD $0xB93E0002 // KIMD --, R2 - BVS continue // continue if interrupted - MOVD $0, R0 // reset R0 for pre-go1.8 compilers - RET - -// func klmd(function code, chain *[200]byte, dst, src []byte) -TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 - // TODO: SHAKE support - MOVD function+0(FP), R0 - MOVD chain+8(FP), R1 - LMG dst+16(FP), R2, R3 // R2=base, R3=len - LMG src+40(FP), R4, R5 // R4=base, R5=len - -continue: - WORD $0xB93F0024 // KLMD R2, R4 - BVS continue // continue if interrupted - MOVD $0, R0 // reset R0 for pre-go1.8 compilers - RET diff --git a/sha3/sha3_test.go b/sha3/sha3_test.go index d97a970b1a..bee9b10d46 100644 --- a/sha3/sha3_test.go +++ b/sha3/sha3_test.go @@ -16,7 +16,6 @@ import ( "encoding" "encoding/hex" "encoding/json" - "fmt" "hash" "io" "math/rand" @@ -523,124 +522,3 @@ func testMarshalUnmarshal(t *testing.T, h hash.Hash) { t.Errorf("got %x, want %x", got, want) } } - -// BenchmarkPermutationFunction measures the speed of the permutation function -// with no input data. -func BenchmarkPermutationFunction(b *testing.B) { - b.SetBytes(int64(200)) - var lanes [25]uint64 - for i := 0; i < b.N; i++ { - keccakF1600(&lanes) - } -} - -// benchmarkHash tests the speed to hash num buffers of buflen each. -func benchmarkHash(b *testing.B, h hash.Hash, size, num int) { - b.StopTimer() - h.Reset() - data := sequentialBytes(size) - b.SetBytes(int64(size * num)) - b.StartTimer() - - var state []byte - for i := 0; i < b.N; i++ { - for j := 0; j < num; j++ { - h.Write(data) - } - state = h.Sum(state[:0]) - } - b.StopTimer() - h.Reset() -} - -// benchmarkShake is specialized to the Shake instances, which don't -// require a copy on reading output. -func benchmarkShake(b *testing.B, h ShakeHash, size, num int) { - b.StopTimer() - h.Reset() - data := sequentialBytes(size) - d := make([]byte, 32) - - b.SetBytes(int64(size * num)) - b.StartTimer() - - for i := 0; i < b.N; i++ { - h.Reset() - for j := 0; j < num; j++ { - h.Write(data) - } - h.Read(d) - } -} - -func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) } -func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) } -func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) } -func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) } - -func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) } -func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) } -func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) } -func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) } - -func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) } - -func Example_sum() { - buf := []byte("some data to hash") - // A hash needs to be 64 bytes long to have 256-bit collision resistance. - h := make([]byte, 64) - // Compute a 64-byte hash of buf and put it in h. - ShakeSum256(h, buf) - fmt.Printf("%x\n", h) - // Output: 0f65fe41fc353e52c55667bb9e2b27bfcc8476f2c413e9437d272ee3194a4e3146d05ec04a25d16b8f577c19b82d16b1424c3e022e783d2b4da98de3658d363d -} - -func Example_mac() { - k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long") - buf := []byte("and this is some data to authenticate") - // A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key. - h := make([]byte, 32) - d := NewShake256() - // Write the key into the hash. - d.Write(k) - // Now write the data. - d.Write(buf) - // Read 32 bytes of output from the hash into h. - d.Read(h) - fmt.Printf("%x\n", h) - // Output: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff -} - -func ExampleNewCShake256() { - out := make([]byte, 32) - msg := []byte("The quick brown fox jumps over the lazy dog") - - // Example 1: Simple cshake - c1 := NewCShake256([]byte("NAME"), []byte("Partition1")) - c1.Write(msg) - c1.Read(out) - fmt.Println(hex.EncodeToString(out)) - - // Example 2: Different customization string produces different digest - c1 = NewCShake256([]byte("NAME"), []byte("Partition2")) - c1.Write(msg) - c1.Read(out) - fmt.Println(hex.EncodeToString(out)) - - // Example 3: Longer output length produces longer digest - out = make([]byte, 64) - c1 = NewCShake256([]byte("NAME"), []byte("Partition1")) - c1.Write(msg) - c1.Read(out) - fmt.Println(hex.EncodeToString(out)) - - // Example 4: Next read produces different result - c1.Read(out) - fmt.Println(hex.EncodeToString(out)) - - // Output: - //a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b - //a8db03e71f3e4da5c4eee9d28333cdd355f51cef3c567e59be5beb4ecdbb28f0 - //a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b9dd98c6ee866ca7dc5a39d53e960f400bcd5a19c8a2d6ec6459f63696543a0d8 - //85e73a72228d08b46515553ca3a29d47df3047e5d84b12d6c2c63e579f4fd1105716b7838e92e981863907f434bfd4443c9e56ea09da998d2f9b47db71988109 -} diff --git a/sha3/shake.go b/sha3/shake.go index a6b3a4281f..6f3f70c265 100644 --- a/sha3/shake.go +++ b/sha3/shake.go @@ -4,24 +4,10 @@ package sha3 -// This file defines the ShakeHash interface, and provides -// functions for creating SHAKE and cSHAKE instances, as well as utility -// functions for hashing bytes to arbitrary-length output. -// -// -// SHAKE implementation is based on FIPS PUB 202 [1] -// cSHAKE implementations is based on NIST SP 800-185 [2] -// -// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf -// [2] https://doi.org/10.6028/NIST.SP.800-185 - import ( - "bytes" - "encoding/binary" - "errors" + "crypto/sha3" "hash" "io" - "math/bits" ) // ShakeHash defines the interface to hash functions that support @@ -32,7 +18,7 @@ type ShakeHash interface { hash.Hash // Read reads more output from the hash; reading affects the hash's - // state. (ShakeHash.Read is thus very different from Hash.Sum) + // state. (ShakeHash.Read is thus very different from Hash.Sum.) // It never returns an error, but subsequent calls to Write or Sum // will panic. io.Reader @@ -41,115 +27,18 @@ type ShakeHash interface { Clone() ShakeHash } -// cSHAKE specific context -type cshakeState struct { - *state // SHA-3 state context and Read/Write operations - - // initBlock is the cSHAKE specific initialization set of bytes. It is initialized - // by newCShake function and stores concatenation of N followed by S, encoded - // by the method specified in 3.3 of [1]. - // It is stored here in order for Reset() to be able to put context into - // initial state. - initBlock []byte -} - -func bytepad(data []byte, rate int) []byte { - out := make([]byte, 0, 9+len(data)+rate-1) - out = append(out, leftEncode(uint64(rate))...) - out = append(out, data...) - if padlen := rate - len(out)%rate; padlen < rate { - out = append(out, make([]byte, padlen)...) - } - return out -} - -func leftEncode(x uint64) []byte { - // Let n be the smallest positive integer for which 2^(8n) > x. - n := (bits.Len64(x) + 7) / 8 - if n == 0 { - n = 1 - } - // Return n || x with n as a byte and x an n bytes in big-endian order. - b := make([]byte, 9) - binary.BigEndian.PutUint64(b[1:], x) - b = b[9-n-1:] - b[0] = byte(n) - return b -} - -func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash { - c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}} - c.initBlock = make([]byte, 0, 9+len(N)+9+len(S)) // leftEncode returns max 9 bytes - c.initBlock = append(c.initBlock, leftEncode(uint64(len(N))*8)...) - c.initBlock = append(c.initBlock, N...) - c.initBlock = append(c.initBlock, leftEncode(uint64(len(S))*8)...) - c.initBlock = append(c.initBlock, S...) - c.Write(bytepad(c.initBlock, c.rate)) - return &c -} - -// Reset resets the hash to initial state. -func (c *cshakeState) Reset() { - c.state.Reset() - c.Write(bytepad(c.initBlock, c.rate)) -} - -// Clone returns copy of a cSHAKE context within its current state. -func (c *cshakeState) Clone() ShakeHash { - b := make([]byte, len(c.initBlock)) - copy(b, c.initBlock) - return &cshakeState{state: c.clone(), initBlock: b} -} - -// Clone returns copy of SHAKE context within its current state. -func (c *state) Clone() ShakeHash { - return c.clone() -} - -func (c *cshakeState) MarshalBinary() ([]byte, error) { - return c.AppendBinary(make([]byte, 0, marshaledSize+len(c.initBlock))) -} - -func (c *cshakeState) AppendBinary(b []byte) ([]byte, error) { - b, err := c.state.AppendBinary(b) - if err != nil { - return nil, err - } - b = append(b, c.initBlock...) - return b, nil -} - -func (c *cshakeState) UnmarshalBinary(b []byte) error { - if len(b) <= marshaledSize { - return errors.New("sha3: invalid hash state") - } - if err := c.state.UnmarshalBinary(b[:marshaledSize]); err != nil { - return err - } - c.initBlock = bytes.Clone(b[marshaledSize:]) - return nil -} - // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. // Its generic security strength is 128 bits against all attacks if at // least 32 bytes of its output are used. func NewShake128() ShakeHash { - return newShake128() + return &shakeWrapper{sha3.NewSHAKE128(), 32, false, sha3.NewSHAKE128} } // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. // Its generic security strength is 256 bits against all attacks if // at least 64 bytes of its output are used. func NewShake256() ShakeHash { - return newShake256() -} - -func newShake128Generic() *state { - return &state{rate: rateK256, outputLen: 32, dsbyte: dsbyteShake} -} - -func newShake256Generic() *state { - return &state{rate: rateK512, outputLen: 64, dsbyte: dsbyteShake} + return &shakeWrapper{sha3.NewSHAKE256(), 64, false, sha3.NewSHAKE256} } // NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, @@ -159,10 +48,9 @@ func newShake256Generic() *state { // computations on same input with different S yield unrelated outputs. // When N and S are both empty, this is equivalent to NewShake128. func NewCShake128(N, S []byte) ShakeHash { - if len(N) == 0 && len(S) == 0 { - return NewShake128() - } - return newCShake(N, S, rateK256, 32, dsbyteCShake) + return &shakeWrapper{sha3.NewCSHAKE128(N, S), 32, false, func() *sha3.SHAKE { + return sha3.NewCSHAKE128(N, S) + }} } // NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, @@ -172,10 +60,9 @@ func NewCShake128(N, S []byte) ShakeHash { // computations on same input with different S yield unrelated outputs. // When N and S are both empty, this is equivalent to NewShake256. func NewCShake256(N, S []byte) ShakeHash { - if len(N) == 0 && len(S) == 0 { - return NewShake256() - } - return newCShake(N, S, rateK512, 64, dsbyteCShake) + return &shakeWrapper{sha3.NewCSHAKE256(N, S), 64, false, func() *sha3.SHAKE { + return sha3.NewCSHAKE256(N, S) + }} } // ShakeSum128 writes an arbitrary-length digest of data into hash. @@ -191,3 +78,42 @@ func ShakeSum256(hash, data []byte) { h.Write(data) h.Read(hash) } + +// shakeWrapper adds the Size, Sum, and Clone methods to a sha3.SHAKE +// to implement the ShakeHash interface. +type shakeWrapper struct { + *sha3.SHAKE + outputLen int + squeezing bool + newSHAKE func() *sha3.SHAKE +} + +func (w *shakeWrapper) Read(p []byte) (n int, err error) { + w.squeezing = true + return w.SHAKE.Read(p) +} + +func (w *shakeWrapper) Clone() ShakeHash { + s := w.newSHAKE() + b, err := w.MarshalBinary() + if err != nil { + panic(err) // unreachable + } + if err := s.UnmarshalBinary(b); err != nil { + panic(err) // unreachable + } + return &shakeWrapper{s, w.outputLen, w.squeezing, w.newSHAKE} +} + +func (w *shakeWrapper) Size() int { return w.outputLen } + +func (w *shakeWrapper) Sum(b []byte) []byte { + if w.squeezing { + panic("sha3: Sum after Read") + } + out := make([]byte, w.outputLen) + // Clone the state so that we don't affect future Write calls. + s := w.Clone() + s.Read(out) + return append(b, out...) +} diff --git a/sha3/shake_noasm.go b/sha3/shake_noasm.go deleted file mode 100644 index 4276ba4ab2..0000000000 --- a/sha3/shake_noasm.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !gc || purego || !s390x - -package sha3 - -func newShake128() *state { - return newShake128Generic() -} - -func newShake256() *state { - return newShake256Generic() -} From 017a1aaa2d993492ef6f74ebe7c87f33d82d3717 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sun, 19 Oct 2025 00:57:52 +0100 Subject: [PATCH 27/37] chacha20poly1305: panic on dst and additionalData overlap The cipher.AEAD interface specifies that these should not overlap. This mirrors the check that the GCM implementation does. Fixes golang/go#75968 Updates golang/go#21624 Change-Id: If5fbb8611ff6c0aae44d50079bad29f56ce00f5b Reviewed-on: https://go-review.googlesource.com/c/crypto/+/712860 Reviewed-by: Roland Shoemaker Reviewed-by: David Chase Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI --- chacha20poly1305/chacha20poly1305_amd64.go | 10 ++++++++-- chacha20poly1305/chacha20poly1305_generic.go | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/chacha20poly1305/chacha20poly1305_amd64.go b/chacha20poly1305/chacha20poly1305_amd64.go index 50695a14f6..b850e772e1 100644 --- a/chacha20poly1305/chacha20poly1305_amd64.go +++ b/chacha20poly1305/chacha20poly1305_amd64.go @@ -56,7 +56,10 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) [] ret, out := sliceForAppend(dst, len(plaintext)+16) if alias.InexactOverlap(out, plaintext) { - panic("chacha20poly1305: invalid buffer overlap") + panic("chacha20poly1305: invalid buffer overlap of output and input") + } + if alias.AnyOverlap(out, additionalData) { + panic("chacha20poly1305: invalid buffer overlap of output and additional data") } chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData) return ret @@ -73,7 +76,10 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ( ciphertext = ciphertext[:len(ciphertext)-16] ret, out := sliceForAppend(dst, len(ciphertext)) if alias.InexactOverlap(out, ciphertext) { - panic("chacha20poly1305: invalid buffer overlap") + panic("chacha20poly1305: invalid buffer overlap of output and input") + } + if alias.AnyOverlap(out, additionalData) { + panic("chacha20poly1305: invalid buffer overlap of output and additional data") } if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) { for i := range out { diff --git a/chacha20poly1305/chacha20poly1305_generic.go b/chacha20poly1305/chacha20poly1305_generic.go index 6313898f0a..2ecc840fca 100644 --- a/chacha20poly1305/chacha20poly1305_generic.go +++ b/chacha20poly1305/chacha20poly1305_generic.go @@ -31,7 +31,10 @@ func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []b ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize) ciphertext, tag := out[:len(plaintext)], out[len(plaintext):] if alias.InexactOverlap(out, plaintext) { - panic("chacha20poly1305: invalid buffer overlap") + panic("chacha20poly1305: invalid buffer overlap of output and input") + } + if alias.AnyOverlap(out, additionalData) { + panic("chacha20poly1305: invalid buffer overlap of output and additional data") } var polyKey [32]byte @@ -67,7 +70,10 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData [] ret, out := sliceForAppend(dst, len(ciphertext)) if alias.InexactOverlap(out, ciphertext) { - panic("chacha20poly1305: invalid buffer overlap") + panic("chacha20poly1305: invalid buffer overlap of output and input") + } + if alias.AnyOverlap(out, additionalData) { + panic("chacha20poly1305: invalid buffer overlap of output and additional data") } if !p.Verify(tag) { for i := range out { From 0997000b45e3a40598272081bcad03ffd21b8adb Mon Sep 17 00:00:00 2001 From: cuishuang Date: Mon, 20 Oct 2025 17:55:48 +0800 Subject: [PATCH 28/37] all: fix some comments Change-Id: I0395c5db6edd7d90f9ec1dadbe881a77c906c732 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/713120 LUCI-TryBot-Result: Go LUCI Reviewed-by: Daniel McCarney Reviewed-by: David Chase Auto-Submit: Sean Liao Reviewed-by: Sean Liao Reviewed-by: Michael Knyszek --- acme/pebble_test.go | 2 +- argon2/argon2.go | 18 +++++++++++------- .../_asm/chacha20poly1305_amd64_asm.go | 4 ++-- chacha20poly1305/chacha20poly1305_test.go | 12 ++++++------ 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/acme/pebble_test.go b/acme/pebble_test.go index bb4809faf7..79051ac821 100644 --- a/acme/pebble_test.go +++ b/acme/pebble_test.go @@ -757,7 +757,7 @@ func prepareBinaries(t *testing.T, pebbleDir string) string { // We don't want to build in the module cache dir, which might not be // writable or to pollute the user's clone with binaries if pebbleLocalDir - //is used. + // is used. binDir := t.TempDir() build := func(cmd string) { diff --git a/argon2/argon2.go b/argon2/argon2.go index 29f0a2de45..2b65ec91ac 100644 --- a/argon2/argon2.go +++ b/argon2/argon2.go @@ -6,7 +6,7 @@ // Argon2 was selected as the winner of the Password Hashing Competition and can // be used to derive cryptographic keys from passwords. // -// For a detailed specification of Argon2 see [1]. +// For a detailed specification of Argon2 see [argon2-specs.pdf]. // // If you aren't sure which function you need, use Argon2id (IDKey) and // the parameter recommendations for your scenario. @@ -17,7 +17,7 @@ // It uses data-independent memory access, which is preferred for password // hashing and password-based key derivation. Argon2i requires more passes over // memory than Argon2id to protect from trade-off attacks. The recommended -// parameters (taken from [2]) for non-interactive operations are time=3 and to +// parameters (taken from [RFC 9106 Section 7.3]) for non-interactive operations are time=3 and to // use the maximum available memory. // // # Argon2id @@ -27,11 +27,11 @@ // half of the first iteration over the memory and data-dependent memory access // for the rest. Argon2id is side-channel resistant and provides better brute- // force cost savings due to time-memory tradeoffs than Argon2i. The recommended -// parameters for non-interactive operations (taken from [2]) are time=1 and to +// parameters for non-interactive operations (taken from [RFC 9106 Section 7.3]) are time=1 and to // use the maximum available memory. // -// [1] https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf -// [2] https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03#section-9.3 +// [argon2-specs.pdf]: https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf +// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3 package argon2 import ( @@ -59,7 +59,7 @@ const ( // // key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32) // -// The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number. +// [RFC 9106 Section 7.3] recommends time=3, and memory=32*1024 as a sensible number. // If using that amount of memory (32 MB) is not possible in some contexts then // the time parameter can be increased to compensate. // @@ -69,6 +69,8 @@ const ( // adjusted to the number of available CPUs. The cost parameters should be // increased as memory latency and CPU parallelism increases. Remember to get a // good random salt. +// +// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3 func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte { return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen) } @@ -83,7 +85,7 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3 // // key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32) // -// The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number. +// [RFC 9106 Section 7.3] recommends time=1, and memory=64*1024 as a sensible number. // If using that amount of memory (64 MB) is not possible in some contexts then // the time parameter can be increased to compensate. // @@ -93,6 +95,8 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3 // adjusted to the numbers of available CPUs. The cost parameters should be // increased as memory latency and CPU parallelism increases. Remember to get a // good random salt. +// +// [RFC 9106 Section 7.3]: https://www.rfc-editor.org/rfc/rfc9106.html#section-7.3 func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte { return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen) } diff --git a/chacha20poly1305/_asm/chacha20poly1305_amd64_asm.go b/chacha20poly1305/_asm/chacha20poly1305_amd64_asm.go index e9ba153b4c..66af868b3c 100644 --- a/chacha20poly1305/_asm/chacha20poly1305_amd64_asm.go +++ b/chacha20poly1305/_asm/chacha20poly1305_amd64_asm.go @@ -641,7 +641,7 @@ func hashADDone() { // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -// Implements the following function fignature: +// Implements the following function signature: // // func chacha20Poly1305Open(dst []byte, key []uint32, src []byte, ad []byte) bool func chacha20Poly1305Open() { @@ -2967,7 +2967,7 @@ func openAVX2Tail512HashEnd() { // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -// Implements the following function fignature: +// Implements the following function signature: // // func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte) func chacha20Poly1305Seal() { diff --git a/chacha20poly1305/chacha20poly1305_test.go b/chacha20poly1305/chacha20poly1305_test.go index 82a4a36102..b38970d177 100644 --- a/chacha20poly1305/chacha20poly1305_test.go +++ b/chacha20poly1305/chacha20poly1305_test.go @@ -153,7 +153,7 @@ func TestRandom(t *testing.T) { t.Run("X", func(t *testing.T) { f(t, NonceSizeX) }) } -func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte, nonceSize int) { +func benchmarkChaCha20Poly1305Seal(b *testing.B, buf []byte, nonceSize int) { b.ReportAllocs() b.SetBytes(int64(len(buf))) @@ -176,7 +176,7 @@ func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte, nonceSize int) { } } -func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte, nonceSize int) { +func benchmarkChaCha20Poly1305Open(b *testing.B, buf []byte, nonceSize int) { b.ReportAllocs() b.SetBytes(int64(len(buf))) @@ -204,17 +204,17 @@ func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte, nonceSize int) { func BenchmarkChacha20Poly1305(b *testing.B) { for _, length := range []int{64, 1350, 8 * 1024} { b.Run("Open-"+strconv.Itoa(length), func(b *testing.B) { - benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSize) + benchmarkChaCha20Poly1305Open(b, make([]byte, length), NonceSize) }) b.Run("Seal-"+strconv.Itoa(length), func(b *testing.B) { - benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSize) + benchmarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSize) }) b.Run("Open-"+strconv.Itoa(length)+"-X", func(b *testing.B) { - benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSizeX) + benchmarkChaCha20Poly1305Open(b, make([]byte, length), NonceSizeX) }) b.Run("Seal-"+strconv.Itoa(length)+"-X", func(b *testing.B) { - benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSizeX) + benchmarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSizeX) }) } } From c0531f9c34514ad5c5551e2d6ce569ca673a8afd Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sun, 26 Oct 2025 13:45:57 +0000 Subject: [PATCH 29/37] all: eliminate vet diagnostics For golang/go#74011 Change-Id: I189c5aba554a578bee1fd351edc30cd5cf4d0ed6 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/714960 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Knyszek Reviewed-by: Daniel McCarney Reviewed-by: David Chase --- otr/otr_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/otr/otr_test.go b/otr/otr_test.go index cfcd062b27..3b7aa1986e 100644 --- a/otr/otr_test.go +++ b/otr/otr_test.go @@ -75,8 +75,8 @@ const libOTRPrivateKey = `(privkeys (account (name "foo@example.com") (protocol prpl-jabber) -(private-key - (dsa +(private-key + (dsa (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#) (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#) (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#) @@ -402,7 +402,7 @@ func TestAgainstLibOTR(t *testing.T) { // This test requires otr.c.test to be built as /tmp/a.out. // If enabled, this tests runs forever performing OTR handshakes in a // loop. - return + t.Skip("This test requires otr.c.test to be built as /tmp/a.out") alicePrivateKey, _ := hex.DecodeString(alicePrivateKeyHex) var alice Conversation From 122a78f140d9d3303ed3261bc374bbbca149140f Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Tue, 11 Nov 2025 08:06:34 -0800 Subject: [PATCH 30/37] go.mod: update golang.org/x dependencies Update golang.org/x dependencies to their latest tagged versions. Change-Id: I0f64669e7c813611f71b1381d9e6fdaba1a39712 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/719641 LUCI-TryBot-Result: Go LUCI Auto-Submit: Gopher Robot Reviewed-by: Dmitri Shuralyov Reviewed-by: David Chase --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index f331951a16..7c5b2e95ae 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module golang.org/x/crypto go 1.24.0 require ( - golang.org/x/net v0.45.0 // tagx:ignore - golang.org/x/sys v0.37.0 - golang.org/x/term v0.36.0 + golang.org/x/net v0.46.0 // tagx:ignore + golang.org/x/sys v0.38.0 + golang.org/x/term v0.37.0 ) -require golang.org/x/text v0.30.0 // indirect +require golang.org/x/text v0.31.0 // indirect diff --git a/go.sum b/go.sum index 6d9f239e86..69212f3190 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= From 79ec3a51fcc7fbd2691d56155d578225ccc542e2 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Sun, 21 Jul 2024 17:17:48 +0200 Subject: [PATCH 31/37] ssh: allow to bind to a hostname in remote forwarding To avoid breaking backwards compatibility, we fix Listen, which receives the address as a string, while ListenTCP can still only be used with IP addresses. Fixes golang/go#33227 Fixes golang/go#37239 Change-Id: I4d45b40fdcb0d6012ed8da59a02149fa37e7db50 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/599995 LUCI-TryBot-Result: Go LUCI Reviewed-by: Junyang Shao Reviewed-by: Bishakh Ghosh Reviewed-by: Filippo Valsorda Auto-Submit: Nicola Murino Reviewed-by: Michael Pratt --- ssh/streamlocal.go | 4 +- ssh/tcpip.go | 124 ++++++++++++++++++++++------------ ssh/test/forward_unix_test.go | 4 ++ 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/ssh/streamlocal.go b/ssh/streamlocal.go index b171b330bc..152470fcb7 100644 --- a/ssh/streamlocal.go +++ b/ssh/streamlocal.go @@ -44,7 +44,7 @@ func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { if !ok { return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer") } - ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"}) + ch := c.forwards.add("unix", socketPath) return &unixListener{socketPath, c, ch}, nil } @@ -96,7 +96,7 @@ func (l *unixListener) Accept() (net.Conn, error) { // Close closes the listener. func (l *unixListener) Close() error { // this also closes the listener. - l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"}) + l.conn.forwards.remove("unix", l.socketPath) m := streamLocalChannelForwardMsg{ l.socketPath, } diff --git a/ssh/tcpip.go b/ssh/tcpip.go index 93d844f035..78c41fe5a1 100644 --- a/ssh/tcpip.go +++ b/ssh/tcpip.go @@ -11,6 +11,7 @@ import ( "io" "math/rand" "net" + "net/netip" "strconv" "strings" "sync" @@ -22,14 +23,21 @@ import ( // the returned net.Listener. The listener must be serviced, or the // SSH connection may hang. // N must be "tcp", "tcp4", "tcp6", or "unix". +// +// If the address is a hostname, it is sent to the remote peer as-is, without +// being resolved locally, and the Listener Addr method will return a zero IP. func (c *Client) Listen(n, addr string) (net.Listener, error) { switch n { case "tcp", "tcp4", "tcp6": - laddr, err := net.ResolveTCPAddr(n, addr) + host, portStr, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + port, err := strconv.ParseInt(portStr, 10, 32) if err != nil { return nil, err } - return c.ListenTCP(laddr) + return c.listenTCPInternal(host, int(port)) case "unix": return c.ListenUnix(addr) default: @@ -102,15 +110,24 @@ func (c *Client) handleForwards() { // ListenTCP requests the remote peer open a listening socket // on laddr. Incoming connections will be available by calling // Accept on the returned net.Listener. +// +// ListenTCP accepts an IP address, to provide a hostname use [Client.Listen] +// with "tcp", "tcp4", or "tcp6" network instead. func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { c.handleForwardsOnce.Do(c.handleForwards) if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { return c.autoPortListenWorkaround(laddr) } + return c.listenTCPInternal(laddr.IP.String(), laddr.Port) +} + +func (c *Client) listenTCPInternal(host string, port int) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) + m := channelForwardMsg{ - laddr.IP.String(), - uint32(laddr.Port), + host, + uint32(port), } // send message ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m)) @@ -123,20 +140,33 @@ func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { // If the original port was 0, then the remote side will // supply a real port number in the response. - if laddr.Port == 0 { + if port == 0 { var p struct { Port uint32 } if err := Unmarshal(resp, &p); err != nil { return nil, err } - laddr.Port = int(p.Port) + port = int(p.Port) } + // Construct a local address placeholder for the remote listener. If the + // original host is an IP address, preserve it so that Listener.Addr() + // reports the same IP. If the host is a hostname or cannot be parsed as an + // IP, fall back to IPv4zero. The port field is always set, even if the + // original port was 0, because in that case the remote server will assign + // one, allowing callers to determine which port was selected. + ip := net.IPv4zero + if parsed, err := netip.ParseAddr(host); err == nil { + ip = net.IP(parsed.AsSlice()) + } + laddr := &net.TCPAddr{ + IP: ip, + Port: port, + } + addr := net.JoinHostPort(host, strconv.FormatInt(int64(port), 10)) + ch := c.forwards.add("tcp", addr) - // Register this forward, using the port number we obtained. - ch := c.forwards.add(laddr) - - return &tcpListener{laddr, c, ch}, nil + return &tcpListener{laddr, addr, c, ch}, nil } // forwardList stores a mapping between remote @@ -149,8 +179,9 @@ type forwardList struct { // forwardEntry represents an established mapping of a laddr on a // remote ssh server to a channel connected to a tcpListener. type forwardEntry struct { - laddr net.Addr - c chan forward + addr string // host:port or socket path + network string // tcp or unix + c chan forward } // forward represents an incoming forwarded tcpip connection. The @@ -161,12 +192,13 @@ type forward struct { raddr net.Addr // the raddr of the incoming connection } -func (l *forwardList) add(addr net.Addr) chan forward { +func (l *forwardList) add(n, addr string) chan forward { l.Lock() defer l.Unlock() f := forwardEntry{ - laddr: addr, - c: make(chan forward, 1), + addr: addr, + network: n, + c: make(chan forward, 1), } l.entries = append(l.entries, f) return f.c @@ -185,19 +217,20 @@ func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) { if port == 0 || port > 65535 { return nil, fmt.Errorf("ssh: port number out of range: %d", port) } - ip := net.ParseIP(string(addr)) - if ip == nil { + ip, err := netip.ParseAddr(addr) + if err != nil { return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr) } - return &net.TCPAddr{IP: ip, Port: int(port)}, nil + return &net.TCPAddr{IP: net.IP(ip.AsSlice()), Port: int(port)}, nil } func (l *forwardList) handleChannels(in <-chan NewChannel) { for ch := range in { var ( - laddr net.Addr - raddr net.Addr - err error + addr string + network string + raddr net.Addr + err error ) switch channelType := ch.ChannelType(); channelType { case "forwarded-tcpip": @@ -207,40 +240,34 @@ func (l *forwardList) handleChannels(in <-chan NewChannel) { continue } - // RFC 4254 section 7.2 specifies that incoming - // addresses should list the address, in string - // format. It is implied that this should be an IP - // address, as it would be impossible to connect to it - // otherwise. - laddr, err = parseTCPAddr(payload.Addr, payload.Port) - if err != nil { - ch.Reject(ConnectionFailed, err.Error()) - continue - } + // RFC 4254 section 7.2 specifies that incoming addresses should + // list the address that was connected, in string format. It is the + // same address used in the tcpip-forward request. The originator + // address is an IP address instead. + addr = net.JoinHostPort(payload.Addr, strconv.FormatUint(uint64(payload.Port), 10)) + raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort) if err != nil { ch.Reject(ConnectionFailed, err.Error()) continue } - + network = "tcp" case "forwarded-streamlocal@openssh.com": var payload forwardedStreamLocalPayload if err = Unmarshal(ch.ExtraData(), &payload); err != nil { ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error()) continue } - laddr = &net.UnixAddr{ - Name: payload.SocketPath, - Net: "unix", - } + addr = payload.SocketPath raddr = &net.UnixAddr{ Name: "@", Net: "unix", } + network = "unix" default: panic(fmt.Errorf("ssh: unknown channel type %s", channelType)) } - if ok := l.forward(laddr, raddr, ch); !ok { + if ok := l.forward(network, addr, raddr, ch); !ok { // Section 7.2, implementations MUST reject spurious incoming // connections. ch.Reject(Prohibited, "no forward for address") @@ -252,11 +279,11 @@ func (l *forwardList) handleChannels(in <-chan NewChannel) { // remove removes the forward entry, and the channel feeding its // listener. -func (l *forwardList) remove(addr net.Addr) { +func (l *forwardList) remove(n, addr string) { l.Lock() defer l.Unlock() for i, f := range l.entries { - if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() { + if n == f.network && addr == f.addr { l.entries = append(l.entries[:i], l.entries[i+1:]...) close(f.c) return @@ -274,11 +301,11 @@ func (l *forwardList) closeAll() { l.entries = nil } -func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool { +func (l *forwardList) forward(n, addr string, raddr net.Addr, ch NewChannel) bool { l.Lock() defer l.Unlock() for _, f := range l.entries { - if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() { + if n == f.network && addr == f.addr { f.c <- forward{newCh: ch, raddr: raddr} return true } @@ -288,6 +315,7 @@ func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool { type tcpListener struct { laddr *net.TCPAddr + addr string conn *Client in <-chan forward @@ -314,13 +342,21 @@ func (l *tcpListener) Accept() (net.Conn, error) { // Close closes the listener. func (l *tcpListener) Close() error { + host, port, err := net.SplitHostPort(l.addr) + if err != nil { + return err + } + rport, err := strconv.ParseUint(port, 10, 32) + if err != nil { + return err + } m := channelForwardMsg{ - l.laddr.IP.String(), - uint32(l.laddr.Port), + host, + uint32(rport), } // this also closes the listener. - l.conn.forwards.remove(l.laddr) + l.conn.forwards.remove("tcp", l.addr) ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) if err == nil && !ok { err = errors.New("ssh: cancel-tcpip-forward failed") diff --git a/ssh/test/forward_unix_test.go b/ssh/test/forward_unix_test.go index c10d1d02a6..549d46cef4 100644 --- a/ssh/test/forward_unix_test.go +++ b/ssh/test/forward_unix_test.go @@ -51,6 +51,8 @@ func testPortForward(t *testing.T, n, listenAddr string) { } }() + // The forwarded address match the listen address because we run the tests + // on the same host. forwardedAddr := sshListener.Addr().String() netConn, err := net.Dial(n, forwardedAddr) if err != nil { @@ -111,6 +113,8 @@ func testPortForward(t *testing.T, n, listenAddr string) { } func TestPortForwardTCP(t *testing.T) { + testPortForward(t, "tcp", ":0") + testPortForward(t, "tcp", "[::]:0") testPortForward(t, "tcp", "localhost:0") } From b4f2b62076abeee4e43fb59544dac565715fbf1e Mon Sep 17 00:00:00 2001 From: Santhanam Date: Sun, 9 Nov 2025 18:35:21 +0000 Subject: [PATCH 32/37] ssh: fix error message on unsupported cipher Until now, when ssh keys using one of these[1] ciphers were passed, we were giving a parse error "ssh: parse error in message type 0". With this fix, we parse it successfully and return the correct error message. [1] aes{128,256}-gcm@openssh.com and chacha20-poly1305@openssh.com Fixes golang/go#52135 Change-Id: I3010fff43c48f29f21edb8d63f44e167861a054e GitHub-Last-Rev: 14ac7e97306d41cba48053b9c60f2ffc7caded45 GitHub-Pull-Request: golang/crypto#324 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/709275 Reviewed-by: Nicola Murino Reviewed-by: Michael Pratt Reviewed-by: Junyang Shao Auto-Submit: Nicola Murino LUCI-TryBot-Result: Go LUCI --- ssh/keys.go | 1 + ssh/keys_test.go | 15 ++++++++++++++ ssh/testdata/keys.go | 47 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/ssh/keys.go b/ssh/keys.go index a035956fcc..47a07539d9 100644 --- a/ssh/keys.go +++ b/ssh/keys.go @@ -1490,6 +1490,7 @@ type openSSHEncryptedPrivateKey struct { NumKeys uint32 PubKey []byte PrivKeyBlock []byte + Rest []byte `ssh:"rest"` } type openSSHPrivateKey struct { diff --git a/ssh/keys_test.go b/ssh/keys_test.go index 661e3cb31c..a1165ec68b 100644 --- a/ssh/keys_test.go +++ b/ssh/keys_test.go @@ -271,6 +271,21 @@ func TestParseEncryptedPrivateKeysWithPassphrase(t *testing.T) { } } +func TestParseEncryptedPrivateKeysWithUnsupportedCiphers(t *testing.T) { + for _, tt := range testdata.UnsupportedCipherData { + t.Run(tt.Name, func(t *testing.T){ + _, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte(tt.EncryptionKey)) + if err == nil { + t.Fatalf("expected 'unknown cipher' error for %q, got nil", tt.Name) + // If this cipher is now supported, remove it from testdata.UnsupportedCipherData + } + if !strings.Contains(err.Error(), "unknown cipher") { + t.Errorf("wanted 'unknown cipher' error, got %v", err.Error()) + } + }) + } +} + func TestParseEncryptedPrivateKeysWithIncorrectPassphrase(t *testing.T) { pem := testdata.PEMEncryptedKeys[0].PEMBytes for i := 0; i < 4096; i++ { diff --git a/ssh/testdata/keys.go b/ssh/testdata/keys.go index 6e48841b67..adb4244eb3 100644 --- a/ssh/testdata/keys.go +++ b/ssh/testdata/keys.go @@ -310,6 +310,53 @@ gbDGyT3bXMQtagvCwoW+/oMTKXiZP5jCJpEO8= }, } +var UnsupportedCipherData = []struct { + Name string + EncryptionKey string + PEMBytes []byte +} { + 0: { + Name: "ed25519-encrypted-chacha20-poly1305", + EncryptionKey: "password", + PEMBytes: []byte(`-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAAHWNoYWNoYTIwLXBvbHkxMzA1QG9wZW5zc2guY29tAAAABm +JjcnlwdAAAABgAAAAQdPyPIjXDRAVHskY0yp9SWwAAAGQAAAABAAAAMwAAAAtzc2gtZWQy +NTUxOQAAACBi6qXITEUrmNce/c2lfozxALlKH3o/6sll8G7wzl1lvQAAAJDNlW1sEkvnK0 +8EecF1vHdPk85yClbh3KkHv09mbGAX/Gk6cJpYEGgJSkO7OEF4kG9DVGGd17+TZbTnM4LD +vYAJZExx2XLgJFEtHCVmJjYzwxx7yC7+s6u/XjrSlZS60RHunOPKyq+C+s48sejXvmX+t5 +0ZoVCI8aftT0ycis3gvLU9sCwJ2UnF6kAV226Z4g2aLkuJbgCDTEcYCRD64K1r +-----END OPENSSH PRIVATE KEY----- +`), + }, + 1: { + Name: "ed25519-encrypted-aes128-gcm", + EncryptionKey: "password", + PEMBytes: []byte(`-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAAFmFlczEyOC1nY21Ab3BlbnNzaC5jb20AAAAGYmNyeXB0AA +AAGAAAABBeMJIOqiyFwNCvDv6f8tQeAAAAZAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAA +IGYpUcb3tGp9kF6pppcUdq3EPMr85BaSUdhiXGbhS5YNAAAAkNBtMEu0UlLgToThuQc+4m +/o0DfFIERu0sspQivn5RJHCtulVKfU9BMiEnF0+LOMOABMlYesgLOtoMxwm4ZCSWH54kZk +vaFyyvvxY+RLDuWNQZCryffIA4+iLCUQR1EdxMDiJweKnGJuD64a+9xTJt47A3Vq4SYzji +EuVmM0FqS8lbT2ynYSe3va0Qyw13jEO5qbtCuyG+C5GejL7kX4Z64= +-----END OPENSSH PRIVATE KEY----- +`), + }, + 2: { + Name: "ed25519-encrypted-aes256-gcm", + EncryptionKey: "password", + PEMBytes: []byte(`-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAAFmFlczI1Ni1nY21Ab3BlbnNzaC5jb20AAAAGYmNyeXB0AA +AAGAAAABBR1p3vH2Wr/HPL+q20L2rjAAAAZAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAA +IM3tT1xrAuOHcrBdoLRo/ojWZsAw2lHfF5hJgFEOts5MAAAAkH/YGrDhDw8u+F8e4P+84B +tAzvp55Lf1Yl7y34BrVmqlWqw/7boqahOp6iYJHNpcuanzc5T6s7Z3wSSYodbY1uvFOfbj +rtP6rIHQIY5J2C40WOYJN8IkZlkwDXwZY0qoE9699ZYmWdwsXRZ7QDhjd2W8ziyZBsttiB +kv2ceuJMLT04TrKc2+RUkj4CQYnz7p8EkgZlUozx8wBSxKFGnkP7k= +-----END OPENSSH PRIVATE KEY----- +`), + }, +} + + // SKData contains a list of PubKeys backed by U2F/FIDO2 Security Keys and their test data. var SKData = []struct { Name string From bcf6a849efcf4702fa5172cb0998b46c3da1e989 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sun, 9 Nov 2025 16:53:06 +0000 Subject: [PATCH 33/37] acme: pass context to request Fixes golang/go#30183 Change-Id: Ic02b34bc87b9465f5c05b2ef5bec157c58809a91 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/719002 Reviewed-by: Junyang Shao Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI --- acme/acme.go | 2 +- acme/http.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/acme/acme.go b/acme/acme.go index 7a51284f91..b53ea28891 100644 --- a/acme/acme.go +++ b/acme/acme.go @@ -690,7 +690,7 @@ func (c *Client) addNonce(h http.Header) { } func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) { - r, err := http.NewRequest("HEAD", url, nil) + r, err := http.NewRequestWithContext(ctx, "HEAD", url, nil) if err != nil { return "", err } diff --git a/acme/http.go b/acme/http.go index 8f29df56ee..7d1052acd4 100644 --- a/acme/http.go +++ b/acme/http.go @@ -128,7 +128,7 @@ func wantStatus(codes ...int) resOkay { func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Response, error) { retry := c.retryTimer() for { - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return nil, err } @@ -228,7 +228,7 @@ func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, if err != nil { return nil, nil, err } - req, err := http.NewRequest("POST", url, bytes.NewReader(b)) + req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(b)) if err != nil { return nil, nil, err } From 2df4153a0311bdfea44376e0eb6ef2faefb0275b Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sun, 9 Nov 2025 12:22:03 +0000 Subject: [PATCH 34/37] acme/autocert: let automatic renewal work with short lifetime certs Fixes golang/go#64997 Fixes golang/go#36548 Change-Id: Idb7a426ad3bfa6ac3b796f4b466da6e3154f1ffa Reviewed-on: https://go-review.googlesource.com/c/crypto/+/719080 Reviewed-by: Roland Shoemaker Reviewed-by: Mark Freeman Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI --- acme/autocert/autocert.go | 18 +++------ acme/autocert/renewal.go | 36 +++++++++--------- acme/autocert/renewal_test.go | 69 ++++++++++++++++++++++++++--------- 3 files changed, 76 insertions(+), 47 deletions(-) diff --git a/acme/autocert/autocert.go b/acme/autocert/autocert.go index ccd5b7e3a1..cde9066f6d 100644 --- a/acme/autocert/autocert.go +++ b/acme/autocert/autocert.go @@ -134,7 +134,8 @@ type Manager struct { // RenewBefore optionally specifies how early certificates should // be renewed before they expire. // - // If zero, they're renewed 30 days before expiration. + // If zero, they're renewed at the lesser of 30 days or + // 1/3 of the certificate lifetime. RenewBefore time.Duration // Client is used to perform low-level operations, such as account registration @@ -464,7 +465,7 @@ func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error leaf: cert.Leaf, } m.state[ck] = s - m.startRenew(ck, s.key, s.leaf.NotAfter) + m.startRenew(ck, s.key, s.leaf.NotBefore, s.leaf.NotAfter) return cert, nil } @@ -610,7 +611,7 @@ func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, } state.cert = der state.leaf = leaf - m.startRenew(ck, state.key, state.leaf.NotAfter) + m.startRenew(ck, state.key, state.leaf.NotBefore, state.leaf.NotAfter) return state.tlscert() } @@ -908,7 +909,7 @@ func httpTokenCacheKey(tokenPath string) string { // // The key argument is a certificate private key. // The exp argument is the cert expiration time (NotAfter). -func (m *Manager) startRenew(ck certKey, key crypto.Signer, exp time.Time) { +func (m *Manager) startRenew(ck certKey, key crypto.Signer, notBefore, notAfter time.Time) { m.renewalMu.Lock() defer m.renewalMu.Unlock() if m.renewal[ck] != nil { @@ -920,7 +921,7 @@ func (m *Manager) startRenew(ck certKey, key crypto.Signer, exp time.Time) { } dr := &domainRenewal{m: m, ck: ck, key: key} m.renewal[ck] = dr - dr.start(exp) + dr.start(notBefore, notAfter) } // stopRenew stops all currently running cert renewal timers. @@ -1028,13 +1029,6 @@ func (m *Manager) hostPolicy() HostPolicy { return defaultHostPolicy } -func (m *Manager) renewBefore() time.Duration { - if m.RenewBefore > renewJitter { - return m.RenewBefore - } - return 720 * time.Hour // 30 days -} - func (m *Manager) now() time.Time { if m.nowFunc != nil { return m.nowFunc() diff --git a/acme/autocert/renewal.go b/acme/autocert/renewal.go index 0df7da78a6..93984f3866 100644 --- a/acme/autocert/renewal.go +++ b/acme/autocert/renewal.go @@ -11,9 +11,6 @@ import ( "time" ) -// renewJitter is the maximum deviation from Manager.RenewBefore. -const renewJitter = time.Hour - // domainRenewal tracks the state used by the periodic timers // renewing a single domain's cert. type domainRenewal struct { @@ -30,13 +27,13 @@ type domainRenewal struct { // defined by the certificate expiration time exp. // // If the timer is already started, calling start is a noop. -func (dr *domainRenewal) start(exp time.Time) { +func (dr *domainRenewal) start(notBefore, notAfter time.Time) { dr.timerMu.Lock() defer dr.timerMu.Unlock() if dr.timer != nil { return } - dr.timer = time.AfterFunc(dr.next(exp), dr.renew) + dr.timer = time.AfterFunc(dr.next(notBefore, notAfter), dr.renew) } // stop stops the cert renewal timer and waits for any in-flight calls to renew @@ -79,7 +76,7 @@ func (dr *domainRenewal) renew() { // TODO: rotate dr.key at some point? next, err := dr.do(ctx) if err != nil { - next = renewJitter / 2 + next = time.Hour / 2 next += time.Duration(pseudoRand.int63n(int64(next))) } testDidRenewLoop(next, err) @@ -107,8 +104,8 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { // a race is likely unavoidable in a distributed environment // but we try nonetheless if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil { - next := dr.next(tlscert.Leaf.NotAfter) - if next > dr.m.renewBefore()+renewJitter { + next := dr.next(tlscert.Leaf.NotBefore, tlscert.Leaf.NotAfter) + if next > 0 { signer, ok := tlscert.PrivateKey.(crypto.Signer) if ok { state := &certState{ @@ -139,18 +136,23 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { return 0, err } dr.updateState(state) - return dr.next(leaf.NotAfter), nil + return dr.next(leaf.NotBefore, leaf.NotAfter), nil } -func (dr *domainRenewal) next(expiry time.Time) time.Duration { - d := expiry.Sub(dr.m.now()) - dr.m.renewBefore() - // add a bit of randomness to renew deadline - n := pseudoRand.int63n(int64(renewJitter)) - d -= time.Duration(n) - if d < 0 { - return 0 +// next returns the wait time before the next renewal should start. +// If manager.RenewBefore is set, it uses that capped at 30 days, +// otherwise it uses a default of 1/3 of the cert lifetime. +// It builds in a jitter of 10% of the renew threshold, capped at 1 hour. +func (dr *domainRenewal) next(notBefore, notAfter time.Time) time.Duration { + threshold := min(notAfter.Sub(notBefore)/3, 30*24*time.Hour) + if dr.m.RenewBefore > 0 { + threshold = min(dr.m.RenewBefore, 30*24*time.Hour) } - return d + maxJitter := min(threshold/10, time.Hour) + jitter := pseudoRand.int63n(int64(maxJitter)) + renewAt := notAfter.Add(-(threshold - time.Duration(jitter))) + renewWait := renewAt.Sub(dr.m.now()) + return max(0, renewWait) } var testDidRenewLoop = func(next time.Duration, err error) {} diff --git a/acme/autocert/renewal_test.go b/acme/autocert/renewal_test.go index ffe4af2a5c..67e2da2e06 100644 --- a/acme/autocert/renewal_test.go +++ b/acme/autocert/renewal_test.go @@ -17,27 +17,60 @@ import ( func TestRenewalNext(t *testing.T) { now := time.Now() - man := &Manager{ - RenewBefore: 7 * 24 * time.Hour, - nowFunc: func() time.Time { return now }, - } - defer man.stopRenew() + nowFn := func() time.Time { return now } tt := []struct { - expiry time.Time - min, max time.Duration + name string + renewBefore time.Duration // arg to Manager + // leaf cert validity + notBefore time.Time + validFor time.Duration + // wait time + waitMin, waitMax time.Duration }{ - {now.Add(90 * 24 * time.Hour), 83*24*time.Hour - renewJitter, 83 * 24 * time.Hour}, - {now.Add(time.Hour), 0, 1}, - {now, 0, 1}, - {now.Add(-time.Hour), 0, 1}, + {"default renewal, 1h cert, valid", + 0, now, time.Hour, 40 * time.Minute, 50 * time.Minute}, + {"default renewal, 1h cert, should renew", + 0, now.Add(-50 * time.Minute), time.Hour, 0, 0}, + {"default renewal, 1h cert, expired", + 0, now.Add(-400 * 24 * time.Hour), time.Hour, 0, 0}, + {"default renewal, 6d cert, valid", + 0, now, 6 * 24 * time.Hour, 4 * 24 * time.Hour, (4*24 + 1) * time.Hour}, + {"default renewal, 6d cert, should renew", + 0, now.Add(-5 * 24 * time.Hour), 6 * 24 * time.Hour, 0, 0}, + {"default renewal, 6d cert, expired", + 0, now.Add(-400 * 24 * time.Hour), 6 * 24 * time.Hour, 0, 0}, + {"default renewal, 90d cert, valid", + 0, now, 90 * 24 * time.Hour, 60 * 24 * time.Hour, (60*24 + 1) * time.Hour}, + {"default renewal, 90d cert, should renew", + 0, now.Add(-70 * 24 * time.Hour), 90 * 24 * time.Hour, 0, 0}, + {"default renewal, 90d cert, expired", + 0, now.Add(-400 * 24 * time.Hour), 90 * 24 * time.Hour, 0, 0}, + {"default renewal, 398d cert, valid", + 0, now, 398 * 24 * time.Hour, (368 * 24) * time.Hour, (368*24 + 1) * time.Hour}, + {"default renewal, 398d cert, should renew", + 0, now.Add(-378 * 24 * time.Hour), 398 * 24 * time.Hour, 0, 0}, + {"default renewal, 398d cert, expired", + 0, now.Add(-400 * 24 * time.Hour), 398 * 24 * time.Hour, 0, 0}, + {"7d renewal, 90d cert, valid", + 7 * 24 * time.Hour, now, 90 * 24 * time.Hour, 83 * 24 * time.Hour, (83*24 + 1) * time.Hour}, + {"7d renewal, 90d cert, should not renew", + 7 * 24 * time.Hour, now.Add(-70 * 24 * time.Hour), 90 * 24 * time.Hour, 13 * 24 * time.Hour, (13*24 + 1) * time.Hour}, + {"7d renewal, 90d cert, should renew", + 7 * 24 * time.Hour, now.Add(-85 * 24 * time.Hour), 90 * 24 * time.Hour, 0, 0}, + {"7d renewal, 90d cert, expired", + 7 * 24 * time.Hour, now.Add(-400 * 24 * time.Hour), 90 * 24 * time.Hour, 0, 0}, } - dr := &domainRenewal{m: man} - for i, test := range tt { - next := dr.next(test.expiry) - if next < test.min || test.max < next { - t.Errorf("%d: next = %v; want between %v and %v", i, next, test.min, test.max) - } + for _, test := range tt { + t.Run(test.name, func(t *testing.T) { + dr := &domainRenewal{m: &Manager{RenewBefore: test.renewBefore, nowFunc: nowFn}} + defer dr.m.stopRenew() + + next := dr.next(test.notBefore, test.notBefore.Add(test.validFor)) + if next < test.waitMin || next > test.waitMax { + t.Errorf("expected wait time: %v <= %v <= %v", test.waitMin, next, test.waitMax) + } + }) } } @@ -239,7 +272,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) { } // trigger renew - man.startRenew(exampleCertKey, s.key, s.leaf.NotAfter) + man.startRenew(exampleCertKey, s.key, s.leaf.NotBefore, s.leaf.NotAfter) <-renewed func() { man.renewalMu.Lock() From f91f7a7c31bf90b39c1de895ad116a2bacc88748 Mon Sep 17 00:00:00 2001 From: Neal Patel Date: Wed, 10 Sep 2025 14:27:42 -0400 Subject: [PATCH 35/37] ssh/agent: prevent panic on malformed constraint An attacker could supply a malformed Constraint that would trigger a panic in a serving agent, effectively causing denial of service. Thank you to Jakub Ciolek for reporting this issue. Fixes CVE-2025-47914 Fixes golang/go#76364 Change-Id: I195bbc68b1560d4f04897722a6a653a7cbf086eb Reviewed-on: https://go-review.googlesource.com/c/crypto/+/721960 LUCI-TryBot-Result: Go LUCI Auto-Submit: Roland Shoemaker Reviewed-by: Damien Neil --- ssh/agent/server.go | 3 +++ ssh/agent/server_test.go | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/ssh/agent/server.go b/ssh/agent/server.go index 88ce4da6c4..4e8ff86b61 100644 --- a/ssh/agent/server.go +++ b/ssh/agent/server.go @@ -203,6 +203,9 @@ func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse for len(constraints) != 0 { switch constraints[0] { case agentConstrainLifetime: + if len(constraints) < 5 { + return 0, false, nil, io.ErrUnexpectedEOF + } lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5]) constraints = constraints[5:] case agentConstrainConfirm: diff --git a/ssh/agent/server_test.go b/ssh/agent/server_test.go index 7700d18f1a..6309e2d9ab 100644 --- a/ssh/agent/server_test.go +++ b/ssh/agent/server_test.go @@ -8,6 +8,7 @@ import ( "crypto" "crypto/rand" "fmt" + "io" pseudorand "math/rand" "reflect" "strings" @@ -258,6 +259,12 @@ func TestParseConstraints(t *testing.T) { t.Errorf("got extension %v, want %v", extensions, expect) } + // Test Malformed Constraint + _, _, _, err = parseConstraints([]byte{1}) + if err != io.ErrUnexpectedEOF { + t.Errorf("got %v, want %v", err, io.ErrUnexpectedEOF) + } + // Test Unknown Constraint _, _, _, err = parseConstraints([]byte{128}) if err == nil || !strings.Contains(err.Error(), "unknown constraint") { From e79546e28b85ea53dd37afe1c4102746ef553b9c Mon Sep 17 00:00:00 2001 From: Neal Patel Date: Wed, 19 Nov 2025 13:35:12 -0500 Subject: [PATCH 36/37] ssh: curb GSSAPI DoS risk by limiting number of specified OIDs Previously, an attacker could specify an integer up to 0xFFFFFFFF that would directly allocate memory despite the observability of the rest of the payload. This change places a hard cap on the amount of mechanisms that can be specified and encoded in the payload. Additionally, it performs a small sanity check to deny payloads whose stated size is contradictory to the observed payload. Thank you to Jakub Ciolek for reporting this issue. Fixes CVE-2025-58181 Fixes golang/go#76363 Change-Id: I0307ab3e906a3f2ae763b5f9f0310f7073f84485 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/721961 Auto-Submit: Roland Shoemaker Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI --- ssh/ssh_gss.go | 8 +++++++- ssh/ssh_gss_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/ssh/ssh_gss.go b/ssh/ssh_gss.go index 24bd7c8e83..a6249a1227 100644 --- a/ssh/ssh_gss.go +++ b/ssh/ssh_gss.go @@ -106,6 +106,13 @@ func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) { if !ok { return nil, errors.New("parse uint32 failed") } + // Each ASN.1 encoded OID must have a minimum + // of 2 bytes; 64 maximum mechanisms is an + // arbitrary, but reasonable ceiling. + const maxMechs = 64 + if n > maxMechs || int(n)*2 > len(rest) { + return nil, errors.New("invalid mechanism count") + } s := &userAuthRequestGSSAPI{ N: n, OIDS: make([]asn1.ObjectIdentifier, n), @@ -122,7 +129,6 @@ func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) { if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil { return nil, err } - } return s, nil } diff --git a/ssh/ssh_gss_test.go b/ssh/ssh_gss_test.go index 39a111288a..9e3ea8c22c 100644 --- a/ssh/ssh_gss_test.go +++ b/ssh/ssh_gss_test.go @@ -17,6 +17,37 @@ func TestParseGSSAPIPayload(t *testing.T) { } } +func TestParseDubiousGSSAPIPayload(t *testing.T) { + for _, tc := range []struct { + name string + payload []byte + wanterr bool + }{ + { + "num mechanisms is unrealistic", + []byte{0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02}, + true, + }, + { + "num mechanisms greater than payload", + []byte{0x00, 0x00, 0x00, 0x40, // 64, |rest| too small + 0x00, 0x00, 0x00, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02}, + true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + _, err := parseGSSAPIPayload(tc.payload) + if tc.wanterr && err == nil { + t.Errorf("got nil, want error") + } + if !tc.wanterr && err != nil { + t.Errorf("got %v, want nil", err) + } + }) + } +} + func TestBuildMIC(t *testing.T) { sessionID := []byte{134, 180, 134, 194, 62, 145, 171, 82, 119, 149, 254, 196, 125, 173, 177, 145, 187, 85, 53, 183, 44, 150, 219, 129, 166, 195, 19, 33, 209, 246, 175, 121} From 4e0068c0098be10d7025c99ab7c50ce454c1f0f9 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Wed, 19 Nov 2025 11:44:35 -0800 Subject: [PATCH 37/37] go.mod: update golang.org/x dependencies Update golang.org/x dependencies to their latest tagged versions. Change-Id: I3923d98d88595230b12db261c48168b863dc2ce9 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/722000 LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Gopher Robot Reviewed-by: Neal Patel --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7c5b2e95ae..ed7433125c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module golang.org/x/crypto go 1.24.0 require ( - golang.org/x/net v0.46.0 // tagx:ignore + golang.org/x/net v0.47.0 // tagx:ignore golang.org/x/sys v0.38.0 golang.org/x/term v0.37.0 ) diff --git a/go.sum b/go.sum index 69212f3190..3a0b108e1d 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=