Compare commits

...

8 Commits

27 changed files with 1329 additions and 0 deletions

42
fyne-gui-test/go.mod Normal file
View File

@@ -0,0 +1,42 @@
module fyne-gui-test
go 1.24.3
require (
fyne.io/fyne/v2 v2.6.3
)
require (
fyne.io/systray v1.11.0 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fredbi/uri v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fyne-io/gl-js v0.2.0 // indirect
github.com/fyne-io/glfw-js v0.3.0 // indirect
github.com/fyne-io/image v0.1.1 // indirect
github.com/fyne-io/oksvg v0.1.0 // indirect
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
github.com/go-text/render v0.2.0 // indirect
github.com/go-text/typesetting v0.2.1 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/hack-pad/go-indexeddb v0.3.2 // indirect
github.com/hack-pad/safejs v0.1.0 // indirect
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rymdport/portal v0.4.1 // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/yuin/goldmark v1.7.8 // indirect
golang.org/x/image v0.24.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

133
fyne-gui-test/go.sum Normal file
View File

@@ -0,0 +1,133 @@
fyne.io/fyne v1.4.3 h1:356CnXCiYrrfaLGsB7qLK3c6ktzyh8WR05v/2RBu51I=
fyne.io/fyne v1.4.3/go.mod h1:8kiPBNSDmuplxs9WnKCkaWYqbcXFy0DeAzwa6PBO9Z8=
fyne.io/fyne/v2 v2.6.3 h1:cvtM2KHeRuH+WhtHiA63z5wJVBkQ9+Ay0UMl9PxFHyA=
fyne.io/fyne/v2 v2.6.3/go.mod h1:NGSurpRElVoI1G3h+ab2df3O5KLGh1CGbsMMcX0bPIs=
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8=
github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fyne-io/gl-js v0.2.0 h1:+EXMLVEa18EfkXBVKhifYB6OGs3HwKO3lUElA0LlAjs=
github.com/fyne-io/gl-js v0.2.0/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI=
github.com/fyne-io/glfw-js v0.3.0 h1:d8k2+Y7l+zy2pc7wlGRyPfTgZoqDf3AI4G+2zOWhWUk=
github.com/fyne-io/glfw-js v0.3.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk=
github.com/fyne-io/image v0.1.1 h1:WH0z4H7qfvNUw5l4p3bC1q70sa5+YWVt6HCj7y4VNyA=
github.com/fyne-io/image v0.1.1/go.mod h1:xrfYBh6yspc+KjkgdZU/ifUC9sPA5Iv7WYUBzQKK7JM=
github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
github.com/fyne-io/oksvg v0.1.0 h1:7EUKk3HV3Y2E+qypp3nWqMXD7mum0hCw2KEGhI1fnBw=
github.com/fyne-io/oksvg v0.1.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI=
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA=
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc=
github.com/go-text/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU=
github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8=
github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M=
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQbSBI91A=
github.com/hack-pad/go-indexeddb v0.3.2/go.mod h1:QvfTevpDVlkfomY498LhstjwbPW6QC4VC/lxYb0Kom0=
github.com/hack-pad/safejs v0.1.0 h1:qPS6vjreAqh2amUqj4WNG1zIw7qlRQJ9K10eDKMCnE8=
github.com/hack-pad/safejs v0.1.0/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade h1:FmusiCI1wHw+XQbvL9M+1r/C3SPqKrmBaIOYwVfQoDE=
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rymdport/portal v0.4.1 h1:2dnZhjf5uEaeDjeF/yBIeeRo6pNI2QAKm7kq1w/kbnA=
github.com/rymdport/portal v0.4.1/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

43
fyne-gui-test/main.go Normal file
View File

@@ -0,0 +1,43 @@
package main
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)
func main() {
myApp := app.New()
window := myApp.NewWindow("Hello World.")
window.Resize(fyne.NewSize(700, 400))
// window.SetFixedSize(true)
textEntry := widget.NewMultiLineEntry()
textEntry.Wrapping = fyne.TextWrapWord
// textEntry.Disable()
initialText := "This is text"
textEntry.SetText(initialText)
textEntry.OnChanged = func(text string) {
if text != initialText {
textEntry.SetText(initialText)
}
}
button := widget.NewButton(" [ Close ] ", func() {
myApp.Quit()
})
content := container.NewBorder(
nil, // top
container.NewBorder(nil, nil, nil, button, nil), // bottom
nil, // left
nil, // right
textEntry, // center
)
window.SetContent(content)
window.CenterOnScreen()
window.ShowAndRun()
}

3
go-ca/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module git.hatter.ink/golang-tests/go-ca
go 1.24.3

75
go-ca/main.go Normal file
View File

@@ -0,0 +1,75 @@
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math"
"math/big"
"time"
)
func main() {
err := innerMain()
if err == nil {
println("Success")
} else {
println("Error: ", err.Error())
}
}
func innerMain() error {
rootKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
if err != nil {
return err
}
rootCert, err := issueRootCertificate(&rootKey.PublicKey, rootKey)
if err != nil {
return err
}
println(string(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: rootCert,
})))
return nil
}
func issueRootCertificate(pubKey, parentPrivKey any) ([]byte, error) {
now := time.Now()
template := x509.Certificate{
SerialNumber: generateSerialNumber(),
Subject: pkix.Name{
CommonName: "Root CA",
},
NotBefore: now.UTC(),
NotAfter: now.AddDate(100, 0, 0).UTC(),
BasicConstraintsValid: true,
IsCA: true,
MaxPathLen: 10,
// MaxPathLenZero: true,
SubjectKeyId: getKeyId(pubKey),
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
}
parentCert := &template
return x509.CreateCertificate(rand.Reader, &template, parentCert, pubKey, parentPrivKey)
}
func getKeyId(pubKey any) []byte {
pubKeyBytes, err := x509.MarshalPKIXPublicKey(pubKey)
if err != nil {
panic("Should not happen")
}
return sha1.New().Sum(pubKeyBytes)
}
func generateSerialNumber() *big.Int {
randInt, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
if err != nil {
panic("Should not happen")
}
return randInt
}

View File

@@ -0,0 +1,8 @@
module git.hatter.ink/go-tpm-non-restricted-key
go 1.24.3
require (
github.com/google/go-tpm v0.9.5 // indirect
golang.org/x/sys v0.8.0 // indirect
)

View File

@@ -0,0 +1,4 @@
github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU=
github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@@ -0,0 +1,211 @@
package main
import (
"crypto"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
"log"
"math/big"
"os"
"github.com/google/go-tpm/legacy/tpm2"
"github.com/google/go-tpm/tpmutil"
)
func generateSrk(f *os.File) {
tmpl := tpm2.Public{
Type: tpm2.AlgRSA,
NameAlg: tpm2.AlgSHA256,
Attributes: tpm2.FlagFixedTPM | // Key can't leave the TPM.
tpm2.FlagFixedParent | // Key can't change parent.
tpm2.FlagSensitiveDataOrigin | // Key created by the TPM (not imported).
tpm2.FlagUserWithAuth | // Uses (empty) password.
tpm2.FlagNoDA | // This flag doesn't do anything, but it's in the spec.
tpm2.FlagRestricted | // Key used for TPM challenges, not general decryption.
tpm2.FlagDecrypt, // Key can be used to decrypt data.
RSAParameters: &tpm2.RSAParams{
Symmetric: &tpm2.SymScheme{Alg: tpm2.AlgAES, KeyBits: 128, Mode: tpm2.AlgCFB},
KeyBits: 2048,
ModulusRaw: make([]byte, 256),
},
}
srk, _, err := tpm2.CreatePrimary(f, tpm2.HandleOwner, tpm2.PCRSelection{}, "", "", tmpl)
if err != nil {
log.Fatalf("creating srk: %v", err)
}
out, err := tpm2.ContextSave(f, srk)
if err != nil {
log.Fatalf("saving context: %v", err)
}
if err := os.WriteFile("srk.ctx", out, 0644); err != nil {
log.Fatalf("writing context: %v", err)
}
}
func generateAppKey(f *os.File) {
srkCtx, err := os.ReadFile("srk.ctx")
if err != nil {
log.Fatalf("read srk: %v", err)
}
srk, err := tpm2.ContextLoad(f, srkCtx)
if err != nil {
log.Fatalf("load srk: %v", err)
}
tmpl := tpm2.Public{
Type: tpm2.AlgECC,
NameAlg: tpm2.AlgSHA256,
Attributes: tpm2.FlagFixedTPM | // Key can't leave the TPM.
tpm2.FlagFixedParent | // Key can't change parent.
tpm2.FlagSensitiveDataOrigin | // Key created by the TPM (not imported).
tpm2.FlagUserWithAuth | // Uses (empty) password.
tpm2.FlagSign, // Key can be used to sign data.
ECCParameters: &tpm2.ECCParams{
Sign: &tpm2.SigScheme{Alg: tpm2.AlgECDSA, Hash: tpm2.AlgSHA256},
CurveID: tpm2.CurveNISTP256,
Point: tpm2.ECPoint{
XRaw: make([]byte, 32),
YRaw: make([]byte, 32),
},
},
}
privBlob, pubBlob, _, hash, ticket, err := tpm2.CreateKey(f, srk, tpm2.PCRSelection{}, "", "", tmpl)
if err != nil {
log.Fatalf("create aik: %v", err)
}
log.Printf("privBlob: %x\n", privBlob)
log.Printf("pubBlob: %x\n", pubBlob)
log.Printf("hash: %x\n", hash)
log.Printf("ticket: %v %s\n", ticket.Type, ticket.Digest)
appKey, _, err := tpm2.Load(f, srk, "", pubBlob, privBlob)
if err != nil {
log.Fatalf("load app key: %v", err)
}
// Write key context to disk.
appKeyCtx, err := tpm2.ContextSave(f, appKey)
if err != nil {
log.Fatalf("saving context: %v", err)
}
if err := os.WriteFile("app.ctx", appKeyCtx, 0644); err != nil {
log.Fatalf("writing context: %v", err)
}
}
func fileExists(filename string) bool {
_, err := os.Stat(filename)
if err == nil {
return true
}
if errors.Is(err, os.ErrNotExist) {
return false
}
panic("Should not happen")
}
type tpmSinger struct {
tpm io.ReadWriter
h tpmutil.Handle
pub crypto.PublicKey
}
func (s *tpmSinger) Public() crypto.PublicKey {
return s.pub
}
func (s *tpmSinger) Sign(r io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
sig, err := tpm2.Sign(s.tpm, s.h, "", digest, nil, nil)
if err != nil {
return nil, fmt.Errorf("signing data: %v", err)
}
if sig.RSA != nil {
return sig.RSA.Signature, nil
}
if sig.ECC != nil {
return asn1.Marshal(struct {
R *big.Int
S *big.Int
}{sig.ECC.R, sig.ECC.S})
}
return nil, fmt.Errorf("unsupported signature type: %v", sig.Alg)
}
func newSigner(tpm io.ReadWriter, h tpmutil.Handle) (*tpmSinger, error) {
tpmPub, _, _, err := tpm2.ReadPublic(tpm, h)
if err != nil {
return nil, fmt.Errorf("read public blob: %v", err)
}
pub, err := tpmPub.Key()
if err != nil {
return nil, fmt.Errorf("decode public key: %v", err)
}
return &tpmSinger{tpm, h, pub}, nil
}
func getSinger(f *os.File) (*tpmSinger, error) {
keyCtx, err := os.ReadFile("app.ctx")
if err != nil {
log.Fatalf("read app key: %v", err)
}
key, err := tpm2.ContextLoad(f, keyCtx)
if err != nil {
log.Fatalf("load app key: %v", err)
}
return newSigner(f, key)
}
// reference: https://ericchiang.github.io/post/tpm-keys/
func main() {
f, err := os.OpenFile("/dev/tpmrm0", os.O_RDWR, 0)
if err != nil {
log.Fatalf("opening tpm: %v", err)
}
defer f.Close()
if !fileExists("srk.ctx") {
generateSrk(f)
}
if !fileExists("app.ctx") {
generateAppKey(f)
}
priv, err := getSinger(f)
if err != nil {
log.Fatalf("create signer: %v", err)
}
publicKeyDer, err := x509.MarshalPKIXPublicKey(priv.Public())
if err != nil {
log.Fatalf("public key: %v", err)
} else {
log.Printf("public key pem: %s\n", base64.StdEncoding.EncodeToString(publicKeyDer))
}
msg := []byte("Hello world!")
digest := sha256.Sum256(msg)
sig, err := priv.Sign(rand.Reader, digest[:], crypto.SHA256)
if err != nil {
log.Fatalf("signing data: %v", err)
}
log.Printf("sig: %s\n", hex.EncodeToString(sig))
pub, ok := priv.Public().(*ecdsa.PublicKey)
if !ok {
log.Fatalf("expected ecdsa.PublicKey got: %T", priv.Public())
}
if !ecdsa.VerifyASN1(pub, digest[:], sig) {
log.Fatalf("failed to verify signature")
}
}

7
go-tpm-rand/go.mod Normal file
View File

@@ -0,0 +1,7 @@
module git.hatter.ink/go-tpm-rand
go 1.24.3
require github.com/google/go-tpm v0.9.5
require golang.org/x/sys v0.8.0 // indirect

4
go-tpm-rand/go.sum Normal file
View File

@@ -0,0 +1,4 @@
github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU=
github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

24
go-tpm-rand/main.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import (
"fmt"
"log"
"os"
"github.com/google/go-tpm/legacy/tpm2"
)
// reference: https://ericchiang.github.io/post/tpm-keys/
func main() {
f, err := os.OpenFile("/dev/tpmrm0", os.O_RDWR, 0)
if err != nil {
log.Fatalf("opening tpm: %v", err)
}
defer f.Close()
out, err := tpm2.GetRandom(f, 16)
if err != nil {
log.Fatalf("getting random bytes: %v", err)
}
fmt.Printf("%x\n", out)
}

5
okta-bcrypt-issue/go.mod Normal file
View File

@@ -0,0 +1,5 @@
module git.hatter.ink/okta-bcrypt-issue
go 1.24.1
require golang.org/x/crypto v0.40.0 // indirect

2
okta-bcrypt-issue/go.sum Normal file
View File

@@ -0,0 +1,2 @@
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=

44
okta-bcrypt-issue/main.go Normal file
View File

@@ -0,0 +1,44 @@
package main
import (
"crypto/rand"
"encoding/base64"
"fmt"
"golang.org/x/crypto/bcrypt"
)
// https://n0rdy.foo/posts/20250121/okta-bcrypt-lessons-for-better-apis/
func main() {
// 18 + 55 + 1 = 74, so above 72 characters' limit of BCrypt
userId := randomString(18)
username := randomString(55)
password := "super-duper-secure-password"
combinedString := fmt.Sprintf("%s:%s:%s", userId, username, password)
combinedHash, err := bcrypt.GenerateFromPassword([]byte(combinedString), bcrypt.DefaultCost)
if err != nil {
panic(err)
}
// let's try to break it
wrongPassword := "wrong-password"
wrongCombinedString := fmt.Sprintf("%s:%s:%s", userId, username, wrongPassword)
err = bcrypt.CompareHashAndPassword(combinedHash, []byte(wrongCombinedString))
if err != nil {
fmt.Println("Password is incorrect")
} else {
fmt.Println("Password is correct")
}
}
func randomString(length int) string {
bytes := make([]byte, length)
_, err := rand.Read(bytes)
if err != nil {
panic(err)
}
return base64.URLEncoding.EncodeToString(bytes)[:length]
}

View File

@@ -0,0 +1,26 @@
> Copied from: https://github.com/skerkour/kerkour.com/tree/main/blog/2023/sha256_length_extension_attacks
# [Breaking SHA256: length extension attacks in practice](https://kerkour.com/sha256-length-extension-attacks)
## Usage
```bash
$ go run ./ -verbose
SecretKey: 7365637265747365637265747365637265747365637265747365637265747365
Legitimate Data: user_id=1&role=user
Legitimate Signature SHA256(SecretKey || LegitimateData): 5b0b4b2472778fea87faac08a72a47d24538bff9d7f19a3a85d069893e2b08ab
Verify LegitimateSignature == SHA256(SecretKey || LegitimateData): true
---------------------------------------------------------------------------------------------------
Malicious Data: &something=true&role=admin
Malicious Message (LegitimateData || padding || MaliciousData):
00000000 75 73 65 72 5f 69 64 3d 31 26 72 6f 6c 65 3d 75 |user_id=1&role=u|
00000010 73 65 72 80 00 00 00 00 00 00 00 00 00 00 01 98 |ser.............|
00000020 26 73 6f 6d 65 74 68 69 6e 67 3d 74 72 75 65 26 |&something=true&|
00000030 72 6f 6c 65 3d 61 64 6d 69 6e |role=admin|
Malicious Signature: 8c37e11e8397b39cba72fa0e4769716c69a7ba9e29cfaf00d4601e086e85dd8f
Verify MaliciousSignature == SHA256(SecretKey, MaliciousMessage): true
```

View File

@@ -0,0 +1,3 @@
module sha256_length_extension_attacks
go 1.22

View File

@@ -0,0 +1,200 @@
package main
import (
"crypto/sha256"
"crypto/subtle"
"encoding/binary"
"encoding/hex"
"flag"
"fmt"
)
var verbose bool
func main() {
flag.BoolVar(&verbose, "verbose", false, "verbose")
flag.Parse()
// 256 bits secretKey
// in real life it should be generated using crypto.Rand
secretKey := []byte("secretsecretsecretsecretsecretse")
legitimateData := []byte("user_id=1&role=user")
legitimateSignature := sign(secretKey, legitimateData)
// sha256 := append(make([]byte, 0), secretKey...)
// // sha256 := make([]byte, 0)
// sha256 = append(sha256, legitimateData...)
// oadding := generatePadding(uint64(len(secretKey)), uint64(len(legitimateData)))
// sha256 = append(sha256, oadding...)
// fmt.Println(hex.Dump(sha256))
fmt.Printf("SecretKey: %s\n", hex.EncodeToString(secretKey))
fmt.Printf("Legitimate Data: %s\n", string(legitimateData))
fmt.Printf("Legitimate Signature SHA256(SecretKey || LegitimateData): %s\n", hex.EncodeToString(legitimateSignature))
fmt.Printf("Verify LegitimateSignature == SHA256(SecretKey || LegitimateData): %v\n", verifySignature(secretKey, legitimateSignature, legitimateData))
fmt.Println("\n---------------------------------------------------------------------------------------------------\n")
maliciousData := []byte("&something=true&role=admin")
maliciousMessage := generateMaliciousMessage(uint64(len(secretKey)), legitimateData, maliciousData)
maliciousSignature := forgeSignature(legitimateSignature, maliciousData, uint64(len(secretKey)+len(legitimateData)))
fmt.Printf("Malicious Data: %s\n", string(maliciousData))
if verbose {
fmt.Println("Malicious Message (LegitimateData || padding || MaliciousData):")
fmt.Println(hex.Dump(maliciousMessage))
}
fmt.Printf("Malicious Signature: %s\n", hex.EncodeToString(maliciousSignature))
fmt.Printf("Verify MaliciousSignature == SHA256(SecretKey, MaliciousMessage): %v\n", verifySignature(secretKey, maliciousSignature, maliciousMessage))
}
// forgeSignature performs a length extension attack by loading a SHA256 hash from the legitimate signature
// and appending the malicious data.
func forgeSignature(legitimateSignature []byte, maliciousData []byte, secretKeyAndDataLength uint64) (forgedSignature []byte) {
digest := loadSha256(legitimateSignature, secretKeyAndDataLength)
digest.Write(maliciousData)
hash := digest.Sum(nil)
forgedSignature = hash[:]
return
}
// generateMaliciousMessage generates the malicious message used to forge a signature without knowing the
// secretKey. The message has the following format: (legitimateData || padding || maliciousData)
func generateMaliciousMessage(secretKeyLength uint64, legitimateData []byte, maliciousData []byte) (message []byte) {
padding := generatePadding(secretKeyLength + uint64(len(legitimateData)))
message = make([]byte, 0, len(legitimateData)+len(padding)+len(maliciousData))
message = append(message, legitimateData...)
message = append(message, padding...)
message = append(message, maliciousData...)
return
}
// generatePadding generates the required padding to fill SHA256 blocks of 512 bits (64 bytes)
// with (secretKey || data || padding)
// The padding format is defined in RFC6234: https://www.rfc-editor.org/rfc/rfc6234#page-8
// inspired by `sha256.go`
func generatePadding(secretKeyAndDataLength uint64) []byte {
var tmp [64 + 8]byte // padding + length buffer
var t uint64
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
tmp[0] = 0x80
if secretKeyAndDataLength%64 < 56 {
t = 56 - secretKeyAndDataLength%64
} else {
t = 64 + 56 - secretKeyAndDataLength%64
}
// Length in bits.
secretKeyAndDataLength <<= 3
padlen := tmp[:t+8]
binary.BigEndian.PutUint64(padlen[t+0:], secretKeyAndDataLength)
return padlen
}
// verifySignature verifies that Signature == SHA256(secretKey || data)
func verifySignature(secretKey []byte, signatureToVerify []byte, data []byte) (isValid bool) {
isValid = false
signature := sign(secretKey, data)
if subtle.ConstantTimeCompare(signature, signatureToVerify) == 1 {
isValid = true
}
return
}
// sign generates a SHA256 MAC such as SHA256(secretKey || data)
func sign(secretKey []byte, data []byte) (signature []byte) {
hasher := sha256.New()
hasher.Write(secretKey)
hasher.Write(data)
hash := hasher.Sum(nil)
signature = hash[:]
return
}
// loadSha256 is a slightly modified version of digest.UnmarshalBinary in order to load the state from a
// normal SHA256 hash instead of the "proprietary version" generated by digest.MarshalBinary
func loadSha256(hashBytes []byte, secretKeyAndDataLength uint64) (hash *digest) {
if len(hashBytes) != sha256.Size {
panic("loadSha256: not a valid SHA256 hash")
}
hash = new(digest)
hash.Reset()
hashBytes, hash.h[0] = consumeUint32(hashBytes)
hashBytes, hash.h[1] = consumeUint32(hashBytes)
hashBytes, hash.h[2] = consumeUint32(hashBytes)
hashBytes, hash.h[3] = consumeUint32(hashBytes)
hashBytes, hash.h[4] = consumeUint32(hashBytes)
hashBytes, hash.h[5] = consumeUint32(hashBytes)
hashBytes, hash.h[6] = consumeUint32(hashBytes)
_, hash.h[7] = consumeUint32(hashBytes)
// hash.len is the nearest upper multiple of 64 of the hashed data (secretKeyAndDataLength)
// hash.len = secretKeyAndDataLength + 64 - (secretKeyAndDataLength % 64)
// hash.nx = int(hash.len % chunk)
// hash.len is the length of consumed bytes, including the paddings
hash.len = secretKeyAndDataLength + uint64(len(generatePadding(secretKeyAndDataLength)))
return
}
// func signBinary(secretKey []byte, data []byte) (signature []byte) {
// hasher := new(digest)
// hasher.Reset()
// hasher.Write(secretKey)
// hasher.Write(data)
// hash := hasher.checkSum()
// signature = hash[:]
// if verbose {
// binary, _ := hasher.MarshalBinary()
// fmt.Println("SHA256 Binary:")
// fmt.Println(hex.Dump(binary))
// }
// return
// }
// func loadSha256Binary(hashBytes []byte, secretKeyAndDataLength uint64) (hash *digest) {
// digestBinary := make([]byte, 0, marshaledSize)
// digestBinary = append(digestBinary, []byte(magic256)...)
// digestBinary = append(digestBinary, hashBytes...)
// digestBinary = append(digestBinary, make([]byte, chunk)...)
// digestBinary = binary.BigEndian.AppendUint64(digestBinary, secretKeyAndDataLength+64-(secretKeyAndDataLength%64))
// hash = new(digest)
// hash.Reset()
// err := hash.UnmarshalBinary(digestBinary)
// if err != nil {
// panic(err)
// }
// if verbose {
// fmt.Println("SHA256 state:")
// fmt.Println(hex.Dump(digestBinary))
// }
// return
// }
// dumpBinary prints 00000000 00000000 00000000 00000001
// func dumpBinary(data []byte) {
// for i, n := range data {
// fmt.Printf("%08b ", n)
// if (i+1)%4 == 0 && i != 0 {
// fmt.Println("")
// }
// }
// fmt.Println("")
// }

View File

@@ -0,0 +1,261 @@
// Copyright 2009 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 sha256 implements the SHA224 and SHA256 hash algorithms as defined
// in FIPS 180-4.
package main
import (
"crypto"
// "crypto/internal/boring"
"encoding/binary"
"errors"
"hash"
)
func init() {
crypto.RegisterHash(crypto.SHA224, New224)
crypto.RegisterHash(crypto.SHA256, New)
}
// The size of a SHA256 checksum in bytes.
const Size = 32
// The size of a SHA224 checksum in bytes.
const Size224 = 28
// The blocksize of SHA256 and SHA224 in bytes.
const BlockSize = 64
const (
chunk = 64
init0 = 0x6A09E667
init1 = 0xBB67AE85
init2 = 0x3C6EF372
init3 = 0xA54FF53A
init4 = 0x510E527F
init5 = 0x9B05688C
init6 = 0x1F83D9AB
init7 = 0x5BE0CD19
init0_224 = 0xC1059ED8
init1_224 = 0x367CD507
init2_224 = 0x3070DD17
init3_224 = 0xF70E5939
init4_224 = 0xFFC00B31
init5_224 = 0x68581511
init6_224 = 0x64F98FA7
init7_224 = 0xBEFA4FA4
)
// digest represents the partial evaluation of a checksum.
type digest struct {
h [8]uint32
x [chunk]byte
nx int
len uint64
is224 bool // mark if this digest is SHA-224
}
const (
magic224 = "sha\x02"
magic256 = "sha\x03"
marshaledSize = len(magic256) + 8*4 + chunk + 8
)
func (d *digest) MarshalBinary() ([]byte, error) {
b := make([]byte, 0, marshaledSize)
if d.is224 {
b = append(b, magic224...)
} else {
b = append(b, magic256...)
}
b = binary.BigEndian.AppendUint32(b, d.h[0])
b = binary.BigEndian.AppendUint32(b, d.h[1])
b = binary.BigEndian.AppendUint32(b, d.h[2])
b = binary.BigEndian.AppendUint32(b, d.h[3])
b = binary.BigEndian.AppendUint32(b, d.h[4])
b = binary.BigEndian.AppendUint32(b, d.h[5])
b = binary.BigEndian.AppendUint32(b, d.h[6])
b = binary.BigEndian.AppendUint32(b, d.h[7])
b = append(b, d.x[:d.nx]...)
b = b[:len(b)+len(d.x)-d.nx] // already zero
b = binary.BigEndian.AppendUint64(b, d.len)
return b, nil
}
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) < len(magic224) || (d.is224 && string(b[:len(magic224)]) != magic224) || (!d.is224 && string(b[:len(magic256)]) != magic256) {
return errors.New("crypto/sha256: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("crypto/sha256: invalid hash state size")
}
b = b[len(magic224):]
b, d.h[0] = consumeUint32(b)
b, d.h[1] = consumeUint32(b)
b, d.h[2] = consumeUint32(b)
b, d.h[3] = consumeUint32(b)
b, d.h[4] = consumeUint32(b)
b, d.h[5] = consumeUint32(b)
b, d.h[6] = consumeUint32(b)
b, d.h[7] = consumeUint32(b)
b = b[copy(d.x[:], b):]
b, d.len = consumeUint64(b)
d.nx = int(d.len % chunk)
return nil
}
func consumeUint64(b []byte) ([]byte, uint64) {
_ = b[7]
x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
return b[8:], x
}
func consumeUint32(b []byte) ([]byte, uint32) {
_ = b[3]
x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
return b[4:], x
}
func (d *digest) Reset() {
if !d.is224 {
d.h[0] = init0
d.h[1] = init1
d.h[2] = init2
d.h[3] = init3
d.h[4] = init4
d.h[5] = init5
d.h[6] = init6
d.h[7] = init7
} else {
d.h[0] = init0_224
d.h[1] = init1_224
d.h[2] = init2_224
d.h[3] = init3_224
d.h[4] = init4_224
d.h[5] = init5_224
d.h[6] = init6_224
d.h[7] = init7_224
}
d.nx = 0
d.len = 0
}
// New returns a new hash.Hash computing the SHA256 checksum. The Hash
// also implements encoding.BinaryMarshaler and
// encoding.BinaryUnmarshaler to marshal and unmarshal the internal
// state of the hash.
func New() hash.Hash {
d := new(digest)
d.Reset()
return d
}
// New224 returns a new hash.Hash computing the SHA224 checksum.
func New224() hash.Hash {
d := new(digest)
d.is224 = true
d.Reset()
return d
}
func (d *digest) Size() int {
if !d.is224 {
return Size
}
return Size224
}
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
block(d, d.x[:])
d.nx = 0
}
p = p[n:]
}
if len(p) >= chunk {
n := len(p) &^ (chunk - 1)
block(d, p[:n])
p = p[n:]
}
if len(p) > 0 {
d.nx = copy(d.x[:], p)
}
return
}
func (d *digest) Sum(in []byte) []byte {
// Make a copy of d so that caller can keep writing and summing.
d0 := *d
hash := d0.checkSum()
if d0.is224 {
return append(in, hash[:Size224]...)
}
return append(in, hash[:]...)
}
func (d *digest) checkSum() [Size]byte {
len := d.len
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
var tmp [64 + 8]byte // padding + length buffer
tmp[0] = 0x80
var t uint64
if len%64 < 56 {
t = 56 - len%64
} else {
t = 64 + 56 - len%64
}
// Length in bits.
len <<= 3
padlen := tmp[:t+8]
binary.BigEndian.PutUint64(padlen[t+0:], len)
d.Write(padlen)
if d.nx != 0 {
panic("d.nx != 0")
}
var digest [Size]byte
binary.BigEndian.PutUint32(digest[0:], d.h[0])
binary.BigEndian.PutUint32(digest[4:], d.h[1])
binary.BigEndian.PutUint32(digest[8:], d.h[2])
binary.BigEndian.PutUint32(digest[12:], d.h[3])
binary.BigEndian.PutUint32(digest[16:], d.h[4])
binary.BigEndian.PutUint32(digest[20:], d.h[5])
binary.BigEndian.PutUint32(digest[24:], d.h[6])
if !d.is224 {
binary.BigEndian.PutUint32(digest[28:], d.h[7])
}
return digest
}
// Sum256 returns the SHA256 checksum of the data.
func Sum256(data []byte) [Size]byte {
var d digest
d.Reset()
d.Write(data)
return d.checkSum()
}
// Sum224 returns the SHA224 checksum of the data.
func Sum224(data []byte) [Size224]byte {
var d digest
d.is224 = true
d.Reset()
d.Write(data)
sum := d.checkSum()
ap := (*[Size224]byte)(sum[:])
return *ap
}

View File

@@ -0,0 +1,128 @@
// Copyright 2009 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.
// SHA256 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
package main
import "math/bits"
var _K = []uint32{
0x428a2f98,
0x71374491,
0xb5c0fbcf,
0xe9b5dba5,
0x3956c25b,
0x59f111f1,
0x923f82a4,
0xab1c5ed5,
0xd807aa98,
0x12835b01,
0x243185be,
0x550c7dc3,
0x72be5d74,
0x80deb1fe,
0x9bdc06a7,
0xc19bf174,
0xe49b69c1,
0xefbe4786,
0x0fc19dc6,
0x240ca1cc,
0x2de92c6f,
0x4a7484aa,
0x5cb0a9dc,
0x76f988da,
0x983e5152,
0xa831c66d,
0xb00327c8,
0xbf597fc7,
0xc6e00bf3,
0xd5a79147,
0x06ca6351,
0x14292967,
0x27b70a85,
0x2e1b2138,
0x4d2c6dfc,
0x53380d13,
0x650a7354,
0x766a0abb,
0x81c2c92e,
0x92722c85,
0xa2bfe8a1,
0xa81a664b,
0xc24b8b70,
0xc76c51a3,
0xd192e819,
0xd6990624,
0xf40e3585,
0x106aa070,
0x19a4c116,
0x1e376c08,
0x2748774c,
0x34b0bcb5,
0x391c0cb3,
0x4ed8aa4a,
0x5b9cca4f,
0x682e6ff3,
0x748f82ee,
0x78a5636f,
0x84c87814,
0x8cc70208,
0x90befffa,
0xa4506ceb,
0xbef9a3f7,
0xc67178f2,
}
func block(dig *digest, p []byte) {
var w [64]uint32
h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
for len(p) >= chunk {
// Can interlace the computation of w with the
// rounds below if needed for speed.
for i := 0; i < 16; i++ {
j := i * 4
w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
}
for i := 16; i < 64; i++ {
v1 := w[i-2]
t1 := (bits.RotateLeft32(v1, -17)) ^ (bits.RotateLeft32(v1, -19)) ^ (v1 >> 10)
v2 := w[i-15]
t2 := (bits.RotateLeft32(v2, -7)) ^ (bits.RotateLeft32(v2, -18)) ^ (v2 >> 3)
w[i] = t1 + w[i-7] + t2 + w[i-16]
}
a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
for i := 0; i < 64; i++ {
t1 := h + ((bits.RotateLeft32(e, -6)) ^ (bits.RotateLeft32(e, -11)) ^ (bits.RotateLeft32(e, -25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
t2 := ((bits.RotateLeft32(a, -2)) ^ (bits.RotateLeft32(a, -13)) ^ (bits.RotateLeft32(a, -22))) + ((a & b) ^ (a & c) ^ (b & c))
h = g
g = f
f = e
e = d + t1
d = c
c = b
b = a
a = t1 + t2
}
h0 += a
h1 += b
h2 += c
h3 += d
h4 += e
h5 += f
h6 += g
h7 += h
p = p[chunk:]
}
dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
}

View File

@@ -0,0 +1,29 @@
// swift-tools-version:4.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "go-swift",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "go_swift",
type: .dynamic,
targets: ["go-swift"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "go-swift",
dependencies: []),
.testTarget(
name: "go-swiftTests",
dependencies: ["go-swift"]),
]
)

15
swift-from-go/README.md Normal file
View File

@@ -0,0 +1,15 @@
# go-swift
> Clone from: https://github.com/onderweg/swift-from-go
Example code, complementing the blog post: ["Calling Swift from Go"](https://dev.to/gerwert/calling-swift-from-go-5dbk)
_Note: this repo is more than 3 years old. Feel free to use it as reference, but don't expect it to work with current versions of Go and Swift._
## Building & Running
```
$ swift build
$ go build -o hello
$ ./hello
```

View File

@@ -0,0 +1,7 @@
@_cdecl("sayHello") // export to C as `sayHello``
public func sayHello(namePtr: UnsafePointer<CChar>?) {
// Creates a new string by copying the null-terminated UTF-8 data (C String)
// referenced by the given pointer.
let name = String(cString: namePtr!)
print("Welcome, \(name)!")
}

View File

@@ -0,0 +1,7 @@
import XCTest
import go_swiftTests
var tests = [XCTestCaseEntry]()
tests += go_swiftTests.allTests()
XCTMain(tests)

View File

@@ -0,0 +1,9 @@
import XCTest
#if !os(macOS)
public func allTests() -> [XCTestCaseEntry] {
return [
testCase(go_swiftTests.allTests),
]
}
#endif

View File

@@ -0,0 +1,15 @@
import XCTest
@testable import go_swift
final class go_swiftTests: XCTestCase {
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(go_swift().text, "Hello, World!")
}
static var allTests = [
("testExample", testExample),
]
}

View File

@@ -0,0 +1,2 @@
// Manually crafted header file for C Library
void sayHello(char* name);

22
swift-from-go/main.go Normal file
View File

@@ -0,0 +1,22 @@
package main
/*
#cgo CFLAGS: -I./include
#cgo LDFLAGS: -L.build/debug/ -lgo_swift
#include <stdlib.h>
#include "include/go_swift.h"
*/
import "C"
import "unsafe"
func main() {
// Convert Go string to C string
cstr := C.CString("Bob")
// Call Swift function `sayHello``
C.sayHello(cstr)
// The C string is allocated in the C heap using malloc.
// Therefore memory must be freed when we're done
C.free(unsafe.Pointer(cstr))
}