diff --git a/Acme/Strfry.hs b/Acme/Strfry.hs
new file mode 100644
--- /dev/null
+++ b/Acme/Strfry.hs
@@ -0,0 +1,12 @@
+-- |
+--
+-- Maintainer:  Elliott Hird
+-- Stability:   experimental
+-- Portability: non-portable (glibc only)
+--
+-- This module just re-exports the @String@-based interface.
+module Acme.Strfry
+  ( module Acme.Strfry.String
+  ) where
+
+import Acme.Strfry.String
diff --git a/Acme/Strfry/ByteString.hs b/Acme/Strfry/ByteString.hs
new file mode 100644
--- /dev/null
+++ b/Acme/Strfry/ByteString.hs
@@ -0,0 +1,21 @@
+-- |
+--
+-- Maintainer:  Elliott Hird
+-- Stability:   experimental
+-- Portability: non-portable (glibc only)
+--
+-- The @ByteString@-based interface to @strfry@.
+module Acme.Strfry.ByteString
+  ( strfry
+  ) where
+
+import Control.Monad
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import Acme.Strfry.Foreign
+
+-- | @strfry s@ returns a pseudorandom anagram of @s@. For more
+-- information, consult the glibc manual:
+-- <http://www.gnu.org/software/libc/manual/html_node/strfry.html>
+strfry :: ByteString -> IO ByteString
+strfry s = B.useAsCString s (c_strfry >=> B.packCString)
diff --git a/Acme/Strfry/Foreign.hs b/Acme/Strfry/Foreign.hs
new file mode 100644
--- /dev/null
+++ b/Acme/Strfry/Foreign.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- |
+--
+-- Maintainer:  Elliott Hird
+-- Stability:   experimental
+-- Portability: non-portable (glibc only)
+--
+-- The raw FFI binding to @strfry@.
+module Acme.Strfry.Foreign
+  ( c_strfry
+  ) where
+
+import Foreign.C.String
+
+foreign import ccall unsafe "string.h strfry"
+  c_strfry :: CString -> IO CString
diff --git a/Acme/Strfry/String.hs b/Acme/Strfry/String.hs
new file mode 100644
--- /dev/null
+++ b/Acme/Strfry/String.hs
@@ -0,0 +1,24 @@
+-- |
+--
+-- Maintainer:  Elliott Hird
+-- Stability:   experimental
+-- Portability: non-portable (glibc only)
+--
+-- The @String@-based interface to @strfry@.
+module Acme.Strfry.String
+  ( strfry
+  ) where
+
+import Control.Monad
+import Foreign.C.String
+import Acme.Strfry.Foreign
+
+-- | @strfry s@ returns a pseudorandom anagram of @s@. For more
+-- information, consult the glibc manual:
+-- <http://www.gnu.org/software/libc/manual/html_node/strfry.html>
+--
+-- This interface is based on @String@, and is likely to behave
+-- unpredictably on codepoints above 255. The @ByteString@-based
+-- interface in "Acme.Strfry.ByteString" is recommended for serious use.
+strfry :: String -> IO String
+strfry s = withCString s (c_strfry >=> peekCString)
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2012, Elliott Hird
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Elliott Hird nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/acme-strfry.cabal b/acme-strfry.cabal
new file mode 100644
--- /dev/null
+++ b/acme-strfry.cabal
@@ -0,0 +1,35 @@
+name:                acme-strfry
+version:             0.1
+synopsis:            A binding to the glibc strfry function.
+description:
+  This library provides a simple interface to the glibc @strfry@
+  function, addressing the perennial programming quandary: \"How do I
+  take good data in string form and painlessly turn it into garbage?\"
+  .
+  For more information, consult the glibc documentation:
+  <http://www.gnu.org/software/libc/manual/html_node/strfry.html>
+  .
+  Both @String@ and @ByteString@ interfaces are offered, as well as
+  the raw FFI binding.
+homepage:            https://github.com/ehird/acme-strfry
+license:             BSD3
+license-file:        LICENSE
+author:              Elliott Hird
+maintainer:          Elliott Hird
+stability:           experimental
+category:            Acme
+build-type:          Simple
+cabal-version:       >=1.6
+
+source-repository head
+  type: git
+  location: https://github.com/ehird/acme-strfry.git
+
+library
+  exposed-modules:
+    Acme.Strfry,
+    Acme.Strfry.String,
+    Acme.Strfry.ByteString,
+    Acme.Strfry.Foreign
+  build-depends: base == 4.*, bytestring == 0.9.*
+  ghc-options: -Wall
