All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jruby.truffle.stdlib.digest.DigestNodes Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. This
 * code is released under a tri EPL/GPL/LGPL license. You can use it,
 * redistribute it and/or modify it under the terms of the:
 *
 * Eclipse Public License version 1.0
 * GNU General Public License version 2
 * GNU Lesser General Public License version 2.1
 */
package org.jruby.truffle.stdlib.digest;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import org.jcodings.specific.ASCIIEncoding;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.core.rope.CodeRange;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.string.ByteList;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.control.JavaException;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

@CoreClass("Truffle::Digest")
public abstract class DigestNodes {

    @TruffleBoundary
    private static MessageDigest getMessageDigestInstance(String name) {
        try {
            return MessageDigest.getInstance(name);
        } catch (NoSuchAlgorithmException e) {
            throw new JavaException(e);
        }
    }

    private static DynamicObject createDigest(RubyContext context, DigestAlgorithm algorithm) {
        return Layouts.DIGEST.createDigest(
                context.getCoreLibrary().getDigestFactory(),
                algorithm,
                getMessageDigestInstance(algorithm.getName()));
    }

    @CoreMethod(names = "md5", onSingleton = true)
    public abstract static class MD5Node extends CoreMethodArrayArgumentsNode {

        @Specialization
        public DynamicObject md5() {
            return createDigest(getContext(), DigestAlgorithm.MD5);
        }

    }

    @CoreMethod(names = "sha1", onSingleton = true)
    public abstract static class SHA1Node extends CoreMethodArrayArgumentsNode {

        @Specialization
        public DynamicObject sha1() {
            return createDigest(getContext(), DigestAlgorithm.SHA1);
        }

    }

    @CoreMethod(names = "sha256", onSingleton = true)
    public abstract static class SHA256Node extends CoreMethodArrayArgumentsNode {

        @Specialization
        public DynamicObject sha256() {
            return createDigest(getContext(), DigestAlgorithm.SHA256);
        }

    }

    @CoreMethod(names = "sha384", onSingleton = true)
    public abstract static class SHA384Node extends CoreMethodArrayArgumentsNode {

        @Specialization
        public DynamicObject sha384() {
            return createDigest(getContext(), DigestAlgorithm.SHA384);
        }

    }

    @CoreMethod(names = "sha512", onSingleton = true)
    public abstract static class SHA512Node extends CoreMethodArrayArgumentsNode {

        @Specialization
        public DynamicObject sha512() {
            return createDigest(getContext(), DigestAlgorithm.SHA512);
        }

    }

    @CoreMethod(names = "update", onSingleton = true, required = 2)
    public abstract static class UpdateNode extends CoreMethodArrayArgumentsNode {

        @Specialization(guards = "isRubyString(message)")
        public DynamicObject update(DynamicObject digestObject, DynamicObject message) {
            final MessageDigest digest = Layouts.DIGEST.getDigest(digestObject);

            RopeOperations.visitBytes(StringOperations.rope(message), (bytes, offset, length) -> digest.update(bytes, offset, length));

            return digestObject;
        }

    }

    @CoreMethod(names = "reset", onSingleton = true, required = 1)
    public abstract static class ResetNode extends CoreMethodArrayArgumentsNode {

        @Specialization
        public DynamicObject reset(DynamicObject digestObject) {
            Layouts.DIGEST.getDigest(digestObject).reset();
            return digestObject;
        }

    }

    @CoreMethod(names = "digest", onSingleton = true, required = 1)
    public abstract static class DigestNode extends CoreMethodArrayArgumentsNode {

        @Specialization
        public DynamicObject digest(DynamicObject digestObject) {
            final MessageDigest digest = Layouts.DIGEST.getDigest(digestObject);

            return createString(RopeOperations.create(
                    cloneAndDigest(digest), ASCIIEncoding.INSTANCE, CodeRange.CR_VALID));
        }

        @TruffleBoundary
        private static byte[] cloneAndDigest(MessageDigest digest) {
            final MessageDigest clonedDigest;

            try {
                clonedDigest = (MessageDigest) digest.clone();
            } catch (CloneNotSupportedException e) {
                throw new JavaException(e);
            }

            return clonedDigest.digest();
        }

    }

    @CoreMethod(names = "digest_length", onSingleton = true, required = 1)
    public abstract static class DigestLengthNode extends CoreMethodArrayArgumentsNode {

        @Specialization
        public int digestLength(DynamicObject digestObject) {
            return Layouts.DIGEST.getAlgorithm(digestObject).getLength();
        }

    }

    @CoreMethod(names = "bubblebabble", onSingleton = true, required = 1)
    public abstract static class BubbleBabbleNode extends CoreMethodArrayArgumentsNode {

        @TruffleBoundary
        @Specialization(guards = "isRubyString(message)")
        public DynamicObject bubblebabble(DynamicObject message) {
            final Rope rope = StringOperations.rope(message);
            return createString(bubblebabble(rope.getBytes(), 0, rope.byteLength()));
        }

        /**
         * Ported from OpenSSH (https://github.com/openssh/openssh-portable/blob/957fbceb0f3166e41b76fdb54075ab3b9cc84cba/sshkey.c#L942-L987)
         *
         * OpenSSH License Notice
         *
         * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
         * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
         * Copyright (c) 2010,2011 Damien Miller.  All rights reserved.
         *
         * Redistribution and use in source and binary forms, with or without
         * modification, are permitted provided that the following conditions
         * are met:
         * 1. Redistributions of source code must retain the above copyright
         *    notice, this list of conditions and the following disclaimer.
         * 2. Redistributions in binary form must reproduce the above copyright
         *    notice, this list of conditions and the following disclaimer in the
         *    documentation and/or other materials provided with the distribution.
         *
         * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
         * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
         * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
         * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
         * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
         * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
         * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
         * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         */
        public static ByteList bubblebabble(byte[] message, int begin, int length) {
            char[] vowels = new char[]{'a', 'e', 'i', 'o', 'u', 'y'};
            char[] consonants = new char[]{'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
                    'n', 'p', 'r', 's', 't', 'v', 'z', 'x'};

            long seed = 1;

            ByteList retval = new ByteList();

            int rounds = (length / 2) + 1;
            retval.append('x');
            for (int i = 0; i < rounds; i++) {
                int idx0, idx1, idx2, idx3, idx4;

                if ((i + 1 < rounds) || (length % 2 != 0)) {
                    long b = message[begin + 2 * i] & 0xFF;
                    idx0 = (int) ((((b >> 6) & 3) + seed) % 6) & 0xFFFFFFFF;
                    idx1 = (int) (((b) >> 2) & 15) & 0xFFFFFFFF;
                    idx2 = (int) (((b & 3) + (seed / 6)) % 6) & 0xFFFFFFFF;
                    retval.append(vowels[idx0]);
                    retval.append(consonants[idx1]);
                    retval.append(vowels[idx2]);
                    if ((i + 1) < rounds) {
                        long b2 = message[begin + (2 * i) + 1] & 0xFF;
                        idx3 = (int) ((b2 >> 4) & 15) & 0xFFFFFFFF;
                        idx4 = (int) ((b2) & 15) & 0xFFFFFFFF;
                        retval.append(consonants[idx3]);
                        retval.append('-');
                        retval.append(consonants[idx4]);
                        seed = ((seed * 5) +
                                ((b * 7) +
                                        b2)) % 36;
                    }
                } else {
                    idx0 = (int) (seed % 6) & 0xFFFFFFFF;
                    idx1 = 16;
                    idx2 = (int) (seed / 6) & 0xFFFFFFFF;
                    retval.append(vowels[idx0]);
                    retval.append(consonants[idx1]);
                    retval.append(vowels[idx2]);
                }
            }
            retval.append('x');

            return retval;
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy